{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7f3d8e52",
   "metadata": {},
   "source": [
    "## 1. 模型定义"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4293e19",
   "metadata": {},
   "source": [
    "### 1.1 深度循环神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "29adfdfa",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "from tqdm import *\n",
    "\n",
    "class DRNN(nn.Module):\n",
    "    def __init__(self, input_size, output_size, hidden_size, num_layers):\n",
    "        super(DRNN, self).__init__()\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True) \n",
    "        # batch_first 为 True时output的tensor为（batch,seq,feature）,否则为（seq,batch,feature）\n",
    "        self.linear = nn.Linear(hidden_size, output_size)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        # 初始化隐藏状态和细胞状态\n",
    "        state = torch.zeros(self.num_layers, x.size(0), self.hidden_size)\n",
    "        # 计算输出和最终隐藏状态\n",
    "        output, _ = self.rnn(x, state)\n",
    "        output = self.linear(output)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ba1404f6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rnn.weight_ih_l0 : torch.Size([64, 16])\n",
      "rnn.weight_hh_l0 : torch.Size([64, 64])\n",
      "rnn.bias_ih_l0 : torch.Size([64])\n",
      "rnn.bias_hh_l0 : torch.Size([64])\n",
      "rnn.weight_ih_l1 : torch.Size([64, 64])\n",
      "rnn.weight_hh_l1 : torch.Size([64, 64])\n",
      "rnn.bias_ih_l1 : torch.Size([64])\n",
      "rnn.bias_hh_l1 : torch.Size([64])\n",
      "linear.weight : torch.Size([16, 64])\n",
      "linear.bias : torch.Size([16])\n"
     ]
    }
   ],
   "source": [
    "# 网络结构\n",
    "model = DRNN(16, 16, 64, 2)\n",
    "for name,parameters in model.named_parameters():\n",
    "    print(name,':',parameters.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53bb152c",
   "metadata": {},
   "source": [
    "### 1.2 双向循环神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "389af29a",
   "metadata": {},
   "outputs": [],
   "source": [
    "class BRNN(nn.Module):\n",
    "    def __init__(self, input_size, output_size, hidden_size, num_layers):\n",
    "        super(BRNN, self).__init__()\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True) # bidirectional为True是双向\n",
    "        self.linear = nn.Linear(hidden_size * 2, output_size)  # 双向网络，因此有双倍hidden_size\n",
    "    \n",
    "    def forward(self, x):\n",
    "        # 初始化隐藏状态\n",
    "        state = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size) # 需要双倍的隐藏层\n",
    "        output, _ = self.rnn(x, state)\n",
    "        output = self.linear(output)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "df525aae",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rnn.weight_ih_l0 : torch.Size([64, 16])\n",
      "rnn.weight_hh_l0 : torch.Size([64, 64])\n",
      "rnn.bias_ih_l0 : torch.Size([64])\n",
      "rnn.bias_hh_l0 : torch.Size([64])\n",
      "rnn.weight_ih_l0_reverse : torch.Size([64, 16])\n",
      "rnn.weight_hh_l0_reverse : torch.Size([64, 64])\n",
      "rnn.bias_ih_l0_reverse : torch.Size([64])\n",
      "rnn.bias_hh_l0_reverse : torch.Size([64])\n",
      "rnn.weight_ih_l1 : torch.Size([64, 128])\n",
      "rnn.weight_hh_l1 : torch.Size([64, 64])\n",
      "rnn.bias_ih_l1 : torch.Size([64])\n",
      "rnn.bias_hh_l1 : torch.Size([64])\n",
      "rnn.weight_ih_l1_reverse : torch.Size([64, 128])\n",
      "rnn.weight_hh_l1_reverse : torch.Size([64, 64])\n",
      "rnn.bias_ih_l1_reverse : torch.Size([64])\n",
      "rnn.bias_hh_l1_reverse : torch.Size([64])\n",
      "linear.weight : torch.Size([16, 128])\n",
      "linear.bias : torch.Size([16])\n"
     ]
    }
   ],
   "source": [
    "# 网络结构\n",
    "model = BRNN(16, 16, 64, 2)\n",
    "for name,parameters in model.named_parameters():\n",
    "    print(name,':',parameters.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca114119",
   "metadata": {},
   "source": [
    "### 1.3 长短期记忆网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f4f734e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "class LSTM(nn.Module):\n",
    "    def __init__(self, input_size, output_size, hidden_size, num_layers):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) # LSTM\n",
    "        self.linear = nn.Linear(hidden_size, output_size)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        output, _ = self.lstm(x)\n",
    "        output = self.linear(output)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5fbf3629",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "lstm.weight_ih_l0 : torch.Size([256, 16])\n",
      "lstm.weight_hh_l0 : torch.Size([256, 64])\n",
      "lstm.bias_ih_l0 : torch.Size([256])\n",
      "lstm.bias_hh_l0 : torch.Size([256])\n",
      "lstm.weight_ih_l1 : torch.Size([256, 64])\n",
      "lstm.weight_hh_l1 : torch.Size([256, 64])\n",
      "lstm.bias_ih_l1 : torch.Size([256])\n",
      "lstm.bias_hh_l1 : torch.Size([256])\n",
      "linear.weight : torch.Size([16, 64])\n",
      "linear.bias : torch.Size([16])\n"
     ]
    }
   ],
   "source": [
    "# 网络结构\n",
    "model = LSTM(16, 16, 64, 2)\n",
    "for name,parameters in model.named_parameters():\n",
    "    print(name,':',parameters.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cceebe63",
   "metadata": {},
   "source": [
    "### 1.4 门控循环单元"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "d83e9830",
   "metadata": {},
   "outputs": [],
   "source": [
    "class GRU(nn.Module):\n",
    "    def __init__(self, input_size, output_size, hidden_size, num_layers):\n",
    "        super(GRU, self).__init__()\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True) # GRU\n",
    "        self.linear = nn.Linear(hidden_size, output_size)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        output, _ = self.gru(x)\n",
    "        output = self.linear(output)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0a6cdc9e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "gru.weight_ih_l0 : torch.Size([192, 16])\n",
      "gru.weight_hh_l0 : torch.Size([192, 64])\n",
      "gru.bias_ih_l0 : torch.Size([192])\n",
      "gru.bias_hh_l0 : torch.Size([192])\n",
      "gru.weight_ih_l1 : torch.Size([192, 64])\n",
      "gru.weight_hh_l1 : torch.Size([192, 64])\n",
      "gru.bias_ih_l1 : torch.Size([192])\n",
      "gru.bias_hh_l1 : torch.Size([192])\n",
      "linear.weight : torch.Size([16, 64])\n",
      "linear.bias : torch.Size([16])\n"
     ]
    }
   ],
   "source": [
    "# 网络结构\n",
    "model = GRU(16, 16, 64, 2)\n",
    "for name,parameters in model.named_parameters():\n",
    "    print(name,':',parameters.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "309105e4",
   "metadata": {},
   "source": [
    "## 2. 模型实验"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed98b2f2",
   "metadata": {},
   "source": [
    "### 2.1 数据集加载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "1361d426",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Open</th>\n",
       "      <th>High</th>\n",
       "      <th>Low</th>\n",
       "      <th>Close</th>\n",
       "      <th>Volume</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2023-02-10</th>\n",
       "      <td>33671.54</td>\n",
       "      <td>33897.31</td>\n",
       "      <td>33591.99</td>\n",
       "      <td>33869.27</td>\n",
       "      <td>289863415.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2023-02-09</th>\n",
       "      <td>34105.61</td>\n",
       "      <td>34252.57</td>\n",
       "      <td>33607.13</td>\n",
       "      <td>33699.88</td>\n",
       "      <td>352340883.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2023-02-08</th>\n",
       "      <td>34132.90</td>\n",
       "      <td>34161.65</td>\n",
       "      <td>33899.79</td>\n",
       "      <td>33949.01</td>\n",
       "      <td>331798754.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2023-02-07</th>\n",
       "      <td>33769.78</td>\n",
       "      <td>34240.00</td>\n",
       "      <td>33634.10</td>\n",
       "      <td>34156.69</td>\n",
       "      <td>362844008.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2023-02-06</th>\n",
       "      <td>33874.44</td>\n",
       "      <td>33962.84</td>\n",
       "      <td>33683.58</td>\n",
       "      <td>33891.02</td>\n",
       "      <td>297051674.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-02-20</th>\n",
       "      <td>25124.91</td>\n",
       "      <td>25179.01</td>\n",
       "      <td>24884.19</td>\n",
       "      <td>24964.75</td>\n",
       "      <td>421529658.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-02-16</th>\n",
       "      <td>25165.94</td>\n",
       "      <td>25432.42</td>\n",
       "      <td>25149.26</td>\n",
       "      <td>25219.38</td>\n",
       "      <td>406774321.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-02-15</th>\n",
       "      <td>25047.82</td>\n",
       "      <td>25203.95</td>\n",
       "      <td>24809.42</td>\n",
       "      <td>25200.37</td>\n",
       "      <td>416778260.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-02-14</th>\n",
       "      <td>24535.82</td>\n",
       "      <td>24925.95</td>\n",
       "      <td>24490.36</td>\n",
       "      <td>24893.49</td>\n",
       "      <td>431152512.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-02-13</th>\n",
       "      <td>24540.33</td>\n",
       "      <td>24705.72</td>\n",
       "      <td>24421.03</td>\n",
       "      <td>24640.45</td>\n",
       "      <td>374415694.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>1258 rows × 5 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                Open      High       Low     Close       Volume\n",
       "Date                                                           \n",
       "2023-02-10  33671.54  33897.31  33591.99  33869.27  289863415.0\n",
       "2023-02-09  34105.61  34252.57  33607.13  33699.88  352340883.0\n",
       "2023-02-08  34132.90  34161.65  33899.79  33949.01  331798754.0\n",
       "2023-02-07  33769.78  34240.00  33634.10  34156.69  362844008.0\n",
       "2023-02-06  33874.44  33962.84  33683.58  33891.02  297051674.0\n",
       "...              ...       ...       ...       ...          ...\n",
       "2018-02-20  25124.91  25179.01  24884.19  24964.75  421529658.0\n",
       "2018-02-16  25165.94  25432.42  25149.26  25219.38  406774321.0\n",
       "2018-02-15  25047.82  25203.95  24809.42  25200.37  416778260.0\n",
       "2018-02-14  24535.82  24925.95  24490.36  24893.49  431152512.0\n",
       "2018-02-13  24540.33  24705.72  24421.03  24640.45  374415694.0\n",
       "\n",
       "[1258 rows x 5 columns]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas_datareader as pdr\n",
    "dji = pdr.DataReader('^DJI', 'stooq')\n",
    "dji"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d2b98813",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.plot(dji['Close'])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "2782c88a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch.utils.data import DataLoader, TensorDataset\n",
    "\n",
    "num = len(dji)                           # 总数据量\n",
    "x = torch.tensor(dji['Close'].to_list())  # 股价列表\n",
    "\n",
    "x = (x - torch.mean(x)) / torch.std(x)\n",
    "\n",
    "seq_len = 16                               # 预测序列长度\n",
    "batch_size = 16                            # 设置批大小\n",
    "\n",
    "X_feature = torch.zeros((num - seq_len, seq_len))      # 构建特征矩阵，num-seq_len行，seq_len列，初始值均为0\n",
    "Y_label = torch.zeros((num - seq_len, seq_len))        # 构建标签矩阵，形状同特征矩阵\n",
    "for i in range(seq_len):\n",
    "    X_feature[:, i] = x[i: num - seq_len + i]    # 为特征矩阵赋值\n",
    "    Y_label[:, i] = x[i+1: num - seq_len + i + 1]    # 为标签矩阵赋值\n",
    "\n",
    "train_loader = DataLoader(TensorDataset(\n",
    "    X_feature[:num-seq_len].unsqueeze(2), Y_label[:num-seq_len]),\n",
    "    batch_size=batch_size, shuffle=True)  # 构建数据加载器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "45bf5013",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义超参数\n",
    "input_size = 1\n",
    "output_size = 1\n",
    "num_hiddens = 64\n",
    "n_layers = 2\n",
    "lr = 0.001\n",
    "\n",
    "\n",
    "# 建立模型\n",
    "model = DRNN(input_size, output_size, num_hiddens, n_layers)\n",
    "criterion = nn.MSELoss(reduction='none')\n",
    "trainer = torch.optim.Adam(model.parameters(), lr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "e78bd092",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  5%|▌         | 1/20 [00:00<00:08,  2.30it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1: Validation loss = 0.0180\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 10%|█         | 2/20 [00:00<00:07,  2.29it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 2: Validation loss = 0.0083\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 15%|█▌        | 3/20 [00:01<00:07,  2.29it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 3: Validation loss = 0.0081\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 20%|██        | 4/20 [00:01<00:06,  2.29it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 4: Validation loss = 0.0079\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 25%|██▌       | 5/20 [00:02<00:06,  2.29it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 5: Validation loss = 0.0078\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 30%|███       | 6/20 [00:02<00:06,  2.28it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 6: Validation loss = 0.0077\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 35%|███▌      | 7/20 [00:03<00:05,  2.27it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 7: Validation loss = 0.0081\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 40%|████      | 8/20 [00:03<00:05,  2.28it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 8: Validation loss = 0.0080\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 45%|████▌     | 9/20 [00:03<00:04,  2.28it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 9: Validation loss = 0.0078\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 50%|█████     | 10/20 [00:04<00:04,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 10: Validation loss = 0.0080\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 55%|█████▌    | 11/20 [00:04<00:03,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 11: Validation loss = 0.0079\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 60%|██████    | 12/20 [00:05<00:03,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 12: Validation loss = 0.0079\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 65%|██████▌   | 13/20 [00:05<00:03,  2.27it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 13: Validation loss = 0.0077\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 70%|███████   | 14/20 [00:06<00:02,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 14: Validation loss = 0.0082\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 75%|███████▌  | 15/20 [00:06<00:02,  2.26it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 15: Validation loss = 0.0080\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 80%|████████  | 16/20 [00:07<00:01,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 16: Validation loss = 0.0077\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 85%|████████▌ | 17/20 [00:07<00:01,  2.26it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 17: Validation loss = 0.0078\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 90%|█████████ | 18/20 [00:07<00:00,  2.28it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 18: Validation loss = 0.0076\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      " 95%|█████████▌| 19/20 [00:08<00:00,  2.28it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 19: Validation loss = 0.0076\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 20/20 [00:08<00:00,  2.27it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 20: Validation loss = 0.0076\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAD4CAYAAADlwTGnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8+yak3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAmNUlEQVR4nO3de3zcdZ3v8dcnk8w0yTRtMkmBJqVpofRCC6WUCir7kEWxeCvrDXAVVJTHiqx6zuoRRVhFfeyyB2W9cNaDygFZRRBcrSuCLrAXdLmEWnqBFktJ25SWprk11+Yyn/PH/JIOYZJMm8uk83s/H495zG9+v+/MfOeXybzn+/3+ft8xd0dERMKnINcVEBGR3FAAiIiElAJARCSkFAAiIiGlABARCanCXFfgaFRWVnptbW2uqyEiclx55plnDrp71fD1x1UA1NbWUldXl+tqiIgcV8xsV6b16gISEQkpBYCISEgpAEREQuq4GgMQkfzU19dHQ0MDPT09ua7KcW3GjBnU1NRQVFSUVXkFgIjkXENDAzNnzqS2thYzy3V1jkvuTlNTEw0NDSxYsCCr+6gLSERyrqenh0QioQ//cTAzEonEUbWisgoAM1trZtvNbIeZXZdhe8zM7g22P2lmtcH6hJk9ZmYdZvbdYfe53Mw2m9kmM3vIzCqzrrWI5B19+I/f0e7DMQPAzCLAbcDFwDLgcjNbNqzYVUCLu58K3ArcHKzvAW4APjvsMQuBbwEXuPsZwCbg2qOq+VG46w/1rH/25cl6eBGR41I2LYA1wA533+nuvcBPgXXDyqwD7gqW7wcuNDNz9053f5xUEKSz4FJqqcgqAybtE/qep3azfuPeyXp4EZHjUjYBUA3sSbvdEKzLWMbd+4E2IDHSA7p7H/AJYDOpD/5lwA8zlTWzq82szszqGhsbs6jua1XNjHGwo/eY7isi4RCJRFi5ciXLly/nne98J62trQDU19djZnznO98ZKnvttddy5513AvDhD3+Y6upqDh8+DMDBgwcZbcqa+vp6li9fPlkv46jkZBDYzIpIBcBZwFxSXUBfyFTW3W9399Xuvrqq6jVTWWQlURqlqfPwsVZXREKguLiYjRs3smXLFioqKrjtttuGts2ZM4dvfetb9PZm/iIZiUS44447pqqqEyabw0D3AvPSbtcE6zKVaQj692cBTaM85koAd38RwMzuA14zuDxREvEYTWoBiBwXvvKrrTz38qEJfcxlc8v423eennX58847j02bNg3drqqq4g1veAN33XUXH//4x19T/jOf+Qy33nprxm2j6enp4ROf+AR1dXUUFhbyzW9+kwsuuICtW7fykY98hN7eXpLJJA888ABz587l/e9/Pw0NDQwMDHDDDTdw6aWXHtXzDZdNC+BpYJGZLTCzKHAZsH5YmfXAlcHye4FHffQfG94LLDOzwa/0bwGez77aR6cyHqOrd4Cu3v7JegoRyRMDAwM88sgjvOtd73rV+s9//vPccsstDAwMvOY+J598Mm984xu5++67j+q5brvtNsyMzZs3c88993DllVfS09PD9773PT796U+zceNG6urqqKmp4aGHHmLu3Lk8++yzbNmyhbVr147rdUIWLQB37zeza4GHgQhwh7tvNbObgDp3X0+q//5uM9sBNJMKCQDMrJ7UIG/UzC4BLnL358zsK8B/mlkfsAv48LhfzQgS8SgATR29lFTo3DeR6exovqlPpO7ublauXMnevXtZunQpb3nLW161feHChbzuda/jJz/5Scb7f+ELX2DdunW8/e1vz/o5H3/8cf76r/8agCVLljB//nxeeOEFzjvvPL7+9a/T0NDAu9/9bhYtWsSKFSv4m7/5Gz7/+c/zjne8g/PPP//YX2wgqzEAd3/Q3U9z91Pc/evBuhuDD3/cvcfd3+fup7r7GnffmXbfWnevcPe4u9e4+3PB+u+5+1J3P8Pd3+nuo3UZjUtlEAAHOzQOICKZDY4B7Nq1C3d/1RjAoC9+8YvcfPPNZOrgWLRoEStXruS+++4bd10+8IEPsH79eoqLi3nb297Go48+ymmnncaGDRtYsWIFX/rSl7jpppvG/TyhOBO4Mh4D0JFAIjKmkpISvv3tb/ONb3yD/v5XdxsvWbKEZcuW8atf/Srjfa+//npuueWWrJ/r/PPP58c//jEAL7zwArt372bx4sXs3LmThQsX8qlPfYp169axadMmXn75ZUpKSvjgBz/I5z73OTZs2HDsLzIQigBIBAHQpBaAiGThrLPO4owzzuCee+55zbbrr7+ehoaGjPc7/fTTWbVqVdbPc80115BMJlmxYgWXXnopd955J7FYjPvuu4/ly5ezcuVKtmzZwhVXXMHmzZtZs2YNK1eu5Ctf+Qpf+tKXjvn1DbLRx2qnl9WrV/ux/CJYT98AS254iM+9dTGfvODUSaiZiIzH888/z9KlS3NdjbyQaV+a2TPuvnp42VC0AGYURYjHCmlsVwtARGRQaA6JqYxHaerUGICITI3NmzfzoQ996FXrYrEYTz75ZI5q9FqhCYDUyWBqAYhMV+6eVzOCrlixgo0bN07pcx5tl34ouoAgNR2EDgMVmZ5mzJhBU1PTUX+AyRGDPwgzY8aMrO8TmhZA5cwYz+xqyXU1RCSDmpoaGhoaONYJHyVl8CchsxWeACiN0tzVy0DSiRTkTzNTJB8UFRVl/TOGMnHC0wUUj+EOzRoIFhEBQhQAg2cDa1poEZGU0ARA+oRwIiISogDQhHAiIq8WogDQhHAiIulCEwBlM4ooLDCdDCYiEghNABQUGBWlUY0BiIgEQhMAkOoG0hiAiEhKqAIgEY9yUOcBiIgAIQuASk0IJyIyJGQBkJoQThNOiYiELAAS8Rg9fUm6egdyXRURkZwLVwCU6mxgEZFBoQqAypmpk8EaNQ4gIhKyACgNJoRTAIiIhCsAhiaE06GgIiLhCoCKYAzgYLtaACIioQqAGUURZs4oVAtARISQBQBoOggRkUGhC4BEaVQBICJClgFgZmvNbLuZ7TCz6zJsj5nZvcH2J82sNlifMLPHzKzDzL477D5RM7vdzF4ws21m9p4JeUVjSE0HoS4gEZExA8DMIsBtwMXAMuByM1s2rNhVQIu7nwrcCtwcrO8BbgA+m+GhrwcOuPtpweP+xzG9gqOUiEc1BiAiQnYtgDXADnff6e69wE+BdcPKrAPuCpbvBy40M3P3Tnd/nFQQDPdR4O8A3D3p7geP6RUcpUQ8RktXL/0Dyal4OhGRaSubAKgG9qTdbgjWZSzj7v1AG5AY6QHNbHaw+FUz22BmPzOzE0Yoe7WZ1ZlZXWNjYxbVHV1VPIo7NHepFSAi4ZarQeBCoAb4g7uvAv4buCVTQXe/3d1Xu/vqqqqqcT9xIj54NrACQETCLZsA2AvMS7tdE6zLWMbMCoFZQNMoj9kEdAE/D27/DFiVRV3GbXBCOB0JJCJhl00APA0sMrMFZhYFLgPWDyuzHrgyWH4v8KiPMul+sO1XwJuCVRcCzx1FvY/Z4IRwagGISNgVjlXA3fvN7FrgYSAC3OHuW83sJqDO3dcDPwTuNrMdQDOpkADAzOqBMiBqZpcAF7n7c8Dng/v8I9AIfGQiX9hIBieEUwtARMJuzAAAcPcHgQeHrbsxbbkHeN8I960dYf0u4M+yrehEKSsupChiOhRUREIvdGcCmxmJ0pgmhBOR0AtdAIBOBhMRgdAGQEw/CiMioRfKAKiMRzmoo4BEJORCGgCpKaFHOVJVRCTvhTIAEqVRDvcn6ewdyHVVRERyJpQBUBlMB6EjgUQkzEIZAEd+HF4BICLhFcoAGGoBaCBYREIs5AGgFoCIhFcoA6AimBFUE8KJSJiFMgCihQWUzSjUyWAiEmqhDAAYPBdALQARCa+QB4BaACISXqENAE0IJyJhF+oAUAtARMIstAFQGY/R2tVH30Ay11UREcmJ0AZAIjgXoEXdQCISUqENgMrgXAAdCSQiYRXeAJips4FFJNxCGwCJUk0IJyLhFt4ACMYANB2EiIRVaAOgbEYh0UgBjeoCEpGQCm0AmFnqZDC1AEQkpEIbABCcDawWgIiEVKgDQBPCiUiYhToAEqUxtQBEJLRCHQCV8SgHO3tx91xXRURkymUVAGa21sy2m9kOM7suw/aYmd0bbH/SzGqD9Qkze8zMOszsuyM89noz2zKuV3GMKuMxevuTtB/uz8XTi4jk1JgBYGYR4DbgYmAZcLmZLRtW7Cqgxd1PBW4Fbg7W9wA3AJ8d4bHfDXQcW9XHLxHXT0OKSHhl0wJYA+xw953u3gv8FFg3rMw64K5g+X7gQjMzd+9098dJBcGrmFkc+J/A14659uN05GQwjQOISPhkEwDVwJ602w3Buoxl3L0faAMSYzzuV4FvAF1Z1XQSVMYHJ4RTAIhI+ORkENjMVgKnuPu/ZFH2ajOrM7O6xsbGCa1HZXxwQjh1AYlI+GQTAHuBeWm3a4J1GcuYWSEwC2ga5THPA1abWT3wOHCamf17poLufru7r3b31VVVVVlUN3sVpRoDEJHwyiYAngYWmdkCM4sClwHrh5VZD1wZLL8XeNRHObbS3f/J3ee6ey3wRuAFd3/T0VZ+vIoiBcwuKVIXkIiEUuFYBdy938yuBR4GIsAd7r7VzG4C6tx9PfBD4G4z2wE0kwoJAIJv+WVA1MwuAS5y9+cm/JUco0RpVFNCi0gojRkAAO7+IPDgsHU3pi33AO8b4b61Yzx2PbA8m3pMhoSmgxCRkAr1mcCQOhJIh4GKSBgpANQCEJGQCn0AJEpjtHX30dufzHVVRESmlAIgOBmspUutABEJl9AHwODJYI3tGgcQkXBRAAxOCNepFoCIhEvoA0ATwolIWIU+ADQhnIiEVegDIB4rJFpYoPmARCR0Qh8AZkZlaVTnAohI6IQ+AAAqZ8bUBSQioaMAQBPCiUg4KQBIHQmkMQARCRsFAKmTwZo6ehnlJwxERPKOAoDUoaC9A0kO9fTnuioiIlNGAcCR+YB0MpiIhIkCAP04vIiEkwKA1JTQoBaAiISLAoC06SA0IZyIhIgCAKgo1RiAiISPAgAojBRQXlKks4FFJFQUAAGdDCYiYaMACFTGowoAEQkVBUAgEdeEcCISLgqAQGpKaAWAiISHAiCQiMc41NNPb38y11UREZkSCoDA4NnAmhZaRMJCARA4Mh+QBoJFJBwUAAH9OLyIhE1WAWBma81su5ntMLPrMmyPmdm9wfYnzaw2WJ8ws8fMrMPMvptWvsTMfm1m28xsq5n9/YS9omOkCeFEJGzGDAAziwC3ARcDy4DLzWzZsGJXAS3ufipwK3BzsL4HuAH4bIaHvsXdlwBnAW8ws4uP7SVMjERcE8KJSLhk0wJYA+xw953u3gv8FFg3rMw64K5g+X7gQjMzd+9098dJBcEQd+9y98eC5V5gA1AzjtcxbqXRCLHCApo0IZyIhEQ2AVAN7Em73RCsy1jG3fuBNiCRTQXMbDbwTuCREbZfbWZ1ZlbX2NiYzUMeEzOjMh7jYLtaACISDjkdBDazQuAe4NvuvjNTGXe/3d1Xu/vqqqqqSa1PZTyqKaFFJDSyCYC9wLy02zXBuoxlgg/1WUBTFo99O/And//HLMpOutSEcGoBiEg4ZBMATwOLzGyBmUWBy4D1w8qsB64Mlt8LPOruPtqDmtnXSAXFZ46qxpOoMq7pIEQkPArHKuDu/WZ2LfAwEAHucPetZnYTUOfu64EfAneb2Q6gmVRIAGBm9UAZEDWzS4CLgEPA9cA2YIOZAXzX3X8wga/tqA1OCe3uBHUSEclbYwYAgLs/CDw4bN2Nacs9wPtGuG/tCA877T5hE6VR+pPOoe5+ZpUU5bo6IiKTSmcCp6maGZwMpvmARCQEFABpEqVBAOhQUBEJAQVAmqEJ4XQoqIiEgAIgTaWmgxCREFEApCkvKcIMGjUhnIiEgAIgTWGkgPKSqFoAIhIKCoBhKuNR/SiMiISCAmCYRGlMZwOLSCgoAIZJxKM6CkhEQkEBMExlXC0AEQkHBcAwlfEo7T399PQN5LoqIiKTSgEwzOBPQzarG0hE8pwCYJhEaXA2sI4EEpE8pwAYpnJwQjiNA4hInlMADFNZqgAQkXBQAAyjCeFEJCwUAMOUxgopLopoSmgRyXsKgAx0MpiIhIECIIOETgYTkRBQAGRQpQnhRCQEFAAZaEI4EQkDBUAGiXiU5s5ekknPdVVERCaNAiCDyniM/qRzqKcv11UREZk0CoAMBs8FUDeQiOQzBUAGgz8Of1ADwSKSxxQAGQwGgI4EEpF8pgDIQF1AIhIGCoAMykuiFBg0KQBEJI8pADKIFBgVpVEOajoIEcljWQWAma01s+1mtsPMrsuwPWZm9wbbnzSz2mB9wsweM7MOM/vusPucbWabg/t828xsQl7RBEmUxjQhnIjktTEDwMwiwG3AxcAy4HIzWzas2FVAi7ufCtwK3Bys7wFuAD6b4aH/Cfg4sCi4rD2WFzBZNCGciOS7bFoAa4Ad7r7T3XuBnwLrhpVZB9wVLN8PXGhm5u6d7v44qSAYYmYnAWXu/oS7O/Aj4JJxvI4JVxmPaQxARPJaNgFQDexJu90QrMtYxt37gTYgMcZjNozxmACY2dVmVmdmdY2NjVlUd2Ik4lGdByAieW3aDwK7++3uvtrdV1dVVU3Z81bGY3Qc7qenb2DKnlNEZCplEwB7gXlpt2uCdRnLmFkhMAtoGuMxa8Z4zJyq1E9DikieyyYAngYWmdkCM4sClwHrh5VZD1wZLL8XeDTo28/I3fcBh8zs3ODonyuAXx517SdRYvDH4XUkkIjkqcKxCrh7v5ldCzwMRIA73H2rmd0E1Ln7euCHwN1mtgNoJhUSAJhZPVAGRM3sEuAid38OuAa4EygGfhNcpo0jPw6vABCR/DRmAAC4+4PAg8PW3Zi23AO8b4T71o6wvg5Ynm1Fp5omhBORfDftB4FzZagFoAAQkTylABhBSbSQkmhEE8KJSN5SAIwiEY/qZDARyVsKgFFUxmM6DFRE8pYCYBSJ0hiNOgxURPKUAmAUlZoQTkTymAJgFJXxGM2dvSSTI57TJiJy3FIAjCIRjzKQdFq7+3JdFRGRCacAGEVi6MfhNQ4gIvlHATCKyqEfh9c4gIjkHwXAKI5MB6EWgIjkHwXAKBKlg9NBKABEJP8oAEZRXhKlwPSbACKSnxQAoygoMCpKY+oCEpG8pAAYQ6V+G1hE8pQCYAyV8ZjGAEQkLykAxpBQC0BE8pQCYAyJUrUARCQ/KQDGUDkzSmfvAN29A7muiojIhFIAjKGyVCeDiUh+UgCMYei3gXUugIjkGQXAGCo1IZyI5CkFwBiGWgA6EkhE8owCYAyJYAygUS0AEckzCoAxFEcjlEYjagGISN5RAGShcmaM3+84yK837eNQj34dTETyQ2GuK3A8eP/qefzf/3iRT/5kA4UFxtnzy7lgyRz+fMkcFs2JY2a5rqKIyFEz9+PnB89Xr17tdXV1OXnu/oEkf9zTymPbDvDotgNs298OQPXsYi5YUsUFi+fw+lMqKY5GclI/kcnQ1HGYmx/axh93t3L63DJWzpvNmfNms2xuGbFCvdePF2b2jLuvfs16BcCx2dfWzb9vb+TRbQf4/Y6DdPUOEC0s4LyFCS5YXMWfLzmBkxMlua7mtNA/kKQ/6cwo0gfG8SKZdO55ejf/8NB2unr7OXdhgu372znQnjoYoihiLDupjDPnzebMmtmsPHk2CxKlFBSoNTwdjSsAzGwt8C0gAvzA3f9+2PYY8CPgbKAJuNTd64NtXwCuAgaAT7n7w8H6/wF8DHBgM/ARd+8ZrR7TKQDSHe4f4KmXmnlsWyOPbT/ASwc7AVhYVcoFi1NdRWfPLw/dB2BrVy8/fnI3d/6hnqaOw9QmSlly0kwWn1DG4hNnsuTEmZxcUaIPjWlmy942vvSLLWzc08q5Cyv42iXLOXXOTNyd/Yd6eHZPK3/c08qze1rZ3NBGZzBNyswZhakwCFoJZ86bxZyZM3L8agTGEQBmFgFeAN4CNABPA5e7+3NpZa4BznD3vzKzy4C/cPdLzWwZcA+wBpgL/BtwGnAi8DiwzN27zew+4EF3v3O0ukzXABjupYOd/Pv2VFfRkzub6R1IEikwFlaWsvSkMpacNJOlJ5Wx9MQyTiiL5d0YQv3BTu74/Uv8rK6B7r4Bzl9Uycp5s9m+v53tr7Szu7mLwbddcVGE006Is/jEmSw+sYwlQTAkghPwcsXdqW/qoq6+mQ27W+jqHeD0uWUsr57F8upZlM0oymn9JkN7Tx/f+O0L/Oi/66kojXL925dyycrqUd+fA0lnx4EOnt3TysaGVChs29/OQDL1B66eXcyZ82axpraCd5w5d+jESpla4wmA84Avu/tbg9tfAHD3v0sr83BQ5r/NrBDYD1QB16WXHSwH7AaeAM4EDgG/AL7t7r8drS7HSwCk6+rt5w87mni2oZXn9x3i+X3t7G3tHtpeXlLEkhPLhoJh2UllnDonfty1Ftydul0tfP8/d/K751+hsMBYt7Kaj52/gCUnlr2qbFdvPy+80sH2/YfYtr+dbftSwdCcNt1GZTzGkhNnBsEwk0Vz4sxPlFJeUjQpgdnTN8CWvW08s6uFul0tbNjVMjT9x8wZhcRjhexrO9JArU2UcHr1LFYEl+VzZzGr5PgMBXfnV5v28bV/fY7GjsN88HXz+exbFzOr+NheT3fvAFtfbmPjntahS0NLN5EC402nVfGes2u4cOkcjSFMoZECIJujgKqBPWm3G4DXjVTG3fvNrA1IBOufGHbf6iAobiEVBN3Ab0f68Dezq4GrAU4++eQsqju9lEQLefOyE3jzshOG1rV197F9fzvP7zvEtv2HeG5fOz95ahc9fUmAjK2FU6vizJ1dTGSadZf0DyR5aOt+vv9fL/HsnlZmlxTxyTedyhXnzWdOWebmf0m0kJXzUl0Fg9ydxo7DqVbC/na2Bdf//MQuDvcnh8rNnFHI/EQJ8xOlzK8ooTZRysmJEuYnSjhh5oysu5Ma2w/zzK4WNuxuoa6+mS17D9E7kHqe2kQJb1qc6rZbXVvOqVVxCgqMgx2H2bK3ja0vH2JzQxsbd7fy6037hh5zXkVxKgyCQFhRPYvy0ugx7NWps7Oxgxt/uZXHdxxkRfUsvn/Fas5M+7sci+JohNW1FayurRha96dX2rl/QwO/+ONeHtl2gFnFRbzzzJN4z6oaVs6bnXet4ONFNi2A9wJr3f1jwe0PAa9z92vTymwJyjQEt18kFRJfBp5w938O1v8Q+A3wCPAAcCnQCvwMuH+w3EiOxxZAtgaSzq6mTp7f1862/YcythaKIkZNeQnzKkqYX5H60JsXXJ9cUUJJdOqO6u043M+9T+/h//3+JRpauqlNlHDVGxfwnrNrJrQeg/vlxcZOdjV1sru5i/qmLnY3ddLQ0k1/8sj7N1ZYwMkVQTgEoTAYFIf7k8G3+2Y27GqhvqkLgGikgBU1s1g9v5xV88s5e375UXVTNHf2svXlNjbvbWPL3tT1nuYjf7Pq2cUsry5jfqKUAjMiBVBglnZJ/fb04HKkwDAzIsH61LIxu6SIFdWzqCkvnpAPy56+Af7PYzv43n/sJFZUwOfeupi/fN38Sf+CMZB0fr/jIA9saODhrfvp6UuysKqU96yq4S/Oqmbu7OJJec7e/mSoj9Cbbl1ANaQC46pg/RXAue5+zWh1yecAGElbdx/b9h3ipYOd7GruYndzF7ubutjV1Mmhnv5Xla2Mx1IfehVHgmEwJKriEzPWsK+tmzt/X89PntpNe08/59SW87HzF/LmpSdMeeukfyDJy6097GruHAqFXU1dqUtz51CLKl2iNDr0zf7s+eUsr5414V0RbV19bAlCYTAY9rf14A5JdwbcOdaD7ypKo6yonsUZNbM4o2Y2Z9TM4oQRWlojeWz7Af72l1vZ3dzFJSvn8sW3L83JYG17Tx8Pbt7HA8/s5an6Zszg9ackeM+qGtYuP/Gov0h0Hu7npYOd7DjQwYuNweVAJy8d7KQ/mWTpSWWcU1vBmgUVrK4tD9UA9XgCoJDUIPCFwF5Sg8AfcPetaWU+CaxIGwR+t7u/38xOB37CkUHgR4BFwGrgDuAcUl1AdwJ17v6d0eoSxgAYTWtXL7ubUx94Q8HQ3Mnupi72Hep51YdMpMCYXVzErJKi1HVxEbNLosF1at3skiizSoJtwe2yGYUURgrYsreNH/zXTv510z4cuHj5iXzs/IWv6saZTtydA+2H2dXURX1TJxFLncA3P1EyLbob3J1kEAhJd5LJ1y4PBLfd4ZVDPWxqaGNTQyubGtr404GOoYHWE8piqTConsUZ81LXmbqe9rV1c9OvnuM3W/ZzSlUpX71kOa8/pXKqX3pGu5u6eGBDAz//YwN7mrspjUa4eMVJvHtVNecuSAx17bk7je2H2dHYwYuNnbw4+GF/oIOX08ZoCgxOrijhlKo4p86JEy0soK6+hT/uaRn6YlCbKOGc2grOWVDBObUV1E6T98ZkGO9hoG8D/pHUYaB3uPvXzewmUh/a681sBnA3cBbQDFzm7juD+14PfBToBz7j7r8J1n+FVBdQP/BH4GPuPuqMawqA7B3uH6ChpXuotdDYcZjWrj5au/s41N0XLPfS2tVH+7CWxHAzY4W0H+6nNBrhsjUn8+HX1zKvQuc45FJ37wDP7Wvj2T2pVsazDa3sbOwc2j6vopgzqmcPtRS27G3j1n97gYGk86kLF/Hx8xcSLZx+M8Ekk6mDCR54poFfb95Hx+F+qmcXc/b8cnY1d7HzQAfth4+8X0ujEU6ZE+eUqjinVJWmrufEmZ8oydiy6+1PsvXlNp6ub+apl1Jdgq1dqeldqmbGOKe2PBUKtRUsPals2o25HSudCCYj6h9Icqinn7buPlq7emnt7qOt68hya1cfNeXFvP+ceXl5+GO+ONTTx5a9bWxqaGNzQyoUGlqOjEdcuGQOX37X6cdNeHf3DvDb5/Zz/zMNvHiggwWDH/CDlzmlnFg2Y1zf2pNJ58XGDp6qb6auvoWnXmoeGneLxwpZNb+cc+aXc3p1GdFIhMKIUVhgRAqMokgBkYLU7cJIwdD6VJmCoExQtqAgp+e7KABEQqi5s5dNDa3ECiOcu7Aib7s4JtLLrd08Xd+curzUwvZX2sf9mGYwq7iI8qDbtbwktTy7JEp5SRGzS6PMLh5cV0R5aWp9cVFkQv5mCgARkWPQ2tXLzoOdDCSdvoEkA0mnP+n0DzgDyeTQcuo6dXt42Z6+AVq7+mjp6qWtO3Xd0plqZQ+eSZ1JtLBgKBh+fs3rKY0d2xF24zkPQEQktGaXRFl18uSdz3G4fyDV5drdR0tnLy1B92vL4DhdZ+q6eBJODlUAiIjkUKwwwpyyyIgnTk6m6XcYgIiITAkFgIhISCkARERCSgEgIhJSCgARkZBSAIiIhJQCQEQkpBQAIiIhdVxNBWFmjcCuY7x7JXBwAqsz0VS/8VH9xkf1G5/pXr/57l41fOVxFQDjYWZ1mebCmC5Uv/FR/cZH9Ruf6V6/kagLSEQkpBQAIiIhFaYAuD3XFRiD6jc+qt/4qH7jM93rl1FoxgBEROTVwtQCEBGRNAoAEZGQyrsAMLO1ZrbdzHaY2XUZtsfM7N5g+5NmVjuFdZtnZo+Z2XNmttXMPp2hzJvMrM3MNgaXG6eqfsHz15vZ5uC5X/P7m5by7WD/bTKzVVNYt8Vp+2WjmR0ys88MKzOl+8/M7jCzA2a2JW1dhZn9zsz+FFyXj3DfK4MyfzKzK6ewfv/bzLYFf79/MbPZI9x31PfCJNbvy2a2N+1v+LYR7jvq//ok1u/etLrVm9nGEe476ftv3Nw9by5ABHgRWAhEgWeBZcPKXAN8L1i+DLh3Cut3ErAqWJ4JvJChfm8C/jWH+7AeqBxl+9uA3wAGnAs8mcO/9X5SJ7jkbP8BfwasArakrfsH4Lpg+Trg5gz3qwB2BtflwXL5FNXvIqAwWL45U/2yeS9MYv2+DHw2i7//qP/rk1W/Ydu/AdyYq/033ku+tQDWADvcfae79wI/BdYNK7MOuCtYvh+40MxsKirn7vvcfUOw3A48D1RPxXNPoHXAjzzlCWC2mZ2Ug3pcCLzo7sd6ZviEcPf/BJqHrU5/j90FXJLhrm8Ffufuze7eAvwOWDsV9XP337p7f3DzCaBmop83WyPsv2xk878+bqPVL/jceD9wz0Q/71TJtwCoBvak3W7gtR+wQ2WCf4I2IDEltUsTdD2dBTyZYfN5Zvasmf3GzE6f2prhwG/N7BkzuzrD9mz28VS4jJH/8XK5/wBOcPd9wfJ+4IQMZabLfvwoqRZdJmO9FybTtUEX1R0jdKFNh/13PvCKu/9phO253H9ZybcAOC6YWRx4APiMux8atnkDqW6NM4HvAL+Y4uq90d1XARcDnzSzP5vi5x+TmUWBdwE/y7A51/vvVTzVFzAtj7U2s+uBfuDHIxTJ1Xvhn4BTgJXAPlLdLNPR5Yz+7X/a/y/lWwDsBeal3a4J1mUsY2aFwCygaUpql3rOIlIf/j92958P3+7uh9y9I1h+ECgys8qpqp+77w2uDwD/QqqpnS6bfTzZLgY2uPsrwzfkev8FXhnsFguuD2Qok9P9aGYfBt4B/GUQUq+RxXthUrj7K+4+4O5J4PsjPG+u918h8G7g3pHK5Gr/HY18C4CngUVmtiD4lngZsH5YmfXA4BEX7wUeHekfYKIFfYY/BJ5392+OUObEwTEJM1tD6m80JQFlZqVmNnNwmdRg4ZZhxdYDVwRHA50LtKV1d0yVEb955XL/pUl/j10J/DJDmYeBi8ysPOjiuChYN+nMbC3wv4B3uXvXCGWyeS9MVv3Sx5T+YoTnzeZ/fTK9Gdjm7g2ZNuZy/x2VXI9CT/SF1FEqL5A6QuD6YN1NpN7sADNIdR3sAJ4CFk5h3d5IqjtgE7AxuLwN+Cvgr4Iy1wJbSR3V8ATw+ims38LgeZ8N6jC4/9LrZ8Btwf7dDKye4r9vKakP9Flp63K2/0gF0T6gj1Q/9FWkxpQeAf4E/BtQEZRdDfwg7b4fDd6HO4CPTGH9dpDqPx98Dw4eFTcXeHC098IU1e/u4L21idSH+knD6xfcfs3/+lTUL1h/5+B7Lq3slO+/8V40FYSISEjlWxeQiIhkSQEgIhJSCgARkZBSAIiIhJQCQEQkpBQAIiIhpQAQEQmp/w+LXp++D0YbyAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练轮次\n",
    "num_epochs = 20\n",
    "rnn_loss_history = []\n",
    "\n",
    "for epoch in tqdm(range(num_epochs)):\n",
    "    # 批量训练\n",
    "    for X, Y in train_loader:\n",
    "        trainer.zero_grad()\n",
    "        y_pred = model(X)\n",
    "        loss = criterion(y_pred.squeeze(), Y.squeeze())\n",
    "        loss.sum().backward()\n",
    "        trainer.step()\n",
    "     # 输出损失\n",
    "    model.eval()\n",
    "    with torch.no_grad():\n",
    "        total_loss = 0\n",
    "        for X, Y in train_loader:\n",
    "            y_pred = model(X)\n",
    "            loss = criterion(y_pred.squeeze(), Y.squeeze())\n",
    "            total_loss += loss.sum()/loss.numel()\n",
    "        avg_loss = total_loss / len(train_loader)\n",
    "        print(f'Epoch {epoch+1}: Validation loss = {avg_loss:.4f}')\n",
    "        rnn_loss_history.append(avg_loss)\n",
    "    \n",
    "# 绘制损失曲线图\n",
    "import matplotlib.pyplot as plt\n",
    "# plt.plot(loss_history, label='loss')\n",
    "plt.plot(rnn_loss_history, label='RNN_loss')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "14c3c4b8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAD4CAYAAADxeG0DAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8+yak3AAAACXBIWXMAAAsTAAALEwEAmpwYAABIr0lEQVR4nO2dd3gc1dWH3zuzTV2WJcvdso0r7hiMqTbG9BJK6Akl+UhCSIAkEAgfYAiEkJCEEnpPIHTCR4npvZnYYINxwzbuTZbVy7a53x+z2qJd9ZVWK533efx45s6dmTO7q9/ePffcc5TWGkEQBCF9MVJtgCAIgtA5RMgFQRDSHBFyQRCENEeEXBAEIc0RIRcEQUhzHKm4aWFhoS4pKUnFrQVBENKWJUuW7NZaFzVt77SQK6WGAf8AigEN3K+1vr2lc0pKSli8eHFnby0IgtCnUEptTNSejBF5APi11voLpVQOsEQp9abWekUSri0IgiC0Qqd95Frr7VrrL0Lb1cBKYEhnrysIgiC0jaROdiqlSoDpwKIExy5USi1WSi0uLS1N5m0FQRD6NEmb7FRKZQPPA5dqrauaHtda3w/cDzBz5kzJCyAIaYjf72fLli00NDSk2pRejcfjYejQoTidzjb1T4qQK6Wc2CL+hNb6hWRcUxCEnseWLVvIycmhpKQEpVSqzemVaK0pKytjy5YtjBw5sk3ndNq1oux38yFgpdb6r529niAIPZeGhgb69+8vIt6FKKXo379/u371JMNHfiDwA+AwpdTS0L9jknBdQRB6ICLiXU97X+NOu1a01h8B8s52A5vK6li/u4Y54wak2hRBEHoQKVnZKXSMo2//gFpfkO9uPkZGRYIALFiwgOzsbKqqqjjkkEM4/PDD+fGPf8yvfvUrJk6cmGrzug0R8jSi1hcEoMYbIMfTttlsQegL3HDDDeHtBx98MIWWpAZJmpVGTFVr+db9A7ZvWpdqUwQhZdx0002MHTuWgw46iNWrVwNw3nnn8dxzzwEwZ86cPpcCREbkacT3zfdxqiBPPvZ3rr3xzmbdK698tY19RvRjUF5GN1so9CWuf/kbVmyLWzLSKSYOzuW64/du9viSJUt46qmnWLp0KYFAgBkzZrDPPvsk1YZ0REbkacQecgEYonazoawucZ9aHxf/60vOffjz7jRNELqFDz/8kJNOOonMzExyc3M54YQTUm1Sj0BG5GmAP2hx5N8+4CTsBbE/dizk9eWLGTnn0Li+q3ZUcZr5Lnq3AuKPC0KyaGnkLHQvMiJPA7ZV1FO7ezNj1ZZwW+7GN+L6VTX4eeObnfzJ+QB/dt6PL2B1p5mC0OUccsghvPjii9TX11NdXc3LL7+capN6BCLkacDW8nr+4fojR5qRCZy88m/i+v3h1ZU89sn68P4HX63tFvsEobuYMWMGp59+OlOnTuXoo49m3333DR/ryyG54lpJA7ZW1HOAERqNz76YLxa9R553N2t2VrO7xssBowsBCFTt5H3XZeHzrOXPwYzfpcJkQegyrr76aq6++uqYtuOPP56CggIA3nvvvRRYlVpkRJ4G7N69O7Iz/jjqnP2gdjdH/O0DznogkjF4cNUyhhuRFMH52z/uTjMFISVccMEF1NXVcdBBB6XalJQhI/IeSFmNF39QMzDPYzdUbbb/n38DjJhNg6s/o70fssFzFputIizfPG5+cz0NuzZDaJ3Q+qxpDK/5hgZ/EI/TTM2DCEI38PDDD6fahJQjI/IeyD43vsX+N78d3vfUbrc3hs8GwJ9RGD42zCjlrTde4suPFvJ756N24+yLqRxxJANVOYde8y8sS9K/C0JvRoS8B3KY8QVvuX7Dlc8uwbI0pq/SPpDRDwCdVRjT3/PdWzzntpcoV+WMhiNvwjXqAAAWeS7m2XfbFlO+aH0ZN/9nZZKeQhCE7kKEvAdyo/Nh9jK24fvyGfbUejF91fYBt70gyMwZGNN/QtWHWNqesc/U9kKhrOEzwsdHLP59m+7780c/wPXxrazbtrv1zoIg9BhEyHsg1ToTgL+67iW46AEc/pCQe2whd+QNiunvCtaxSg+3j00/G4CivMzw8f3rPwQrcUz5Pz/bSMmVr3Li3z/igqxP+bXzOb579qqkPo8gCF2LCHkKqPcF8QaCzR6vwxPeNjd9hDNQQwAHOOx2MzviWnkt4xg8Vj0+HOzImwZz7bCsLLeDQMGYcL9ARWQxUTQfvfQwGzxn8fdd57Gzyq5Icnj5M6DFry4I6YIIeQo46NqnueHuR5s9Hoh6W6z6Spz+auqNLAgteHBk5IaPVzsLceMlAy9+dz8wIuc6frmYl6beC8Ab770bd58Gf5D7XLcB9qTp9c7HIjbUlHXo2QShqzFNk2nTpjFp0iSOP/54KioqANiwYQNKKe68885w34svvphHH30UsDMkDhkyBK/XC9hhvSUlJd1m96OPPsrFF1/cJdcWIe8GVm6v4k+vrUJrTa03wEL3Vdy051fN9g8SCRe0fA24AjV4HdnhNmdGZDvoyAKgQFWhTXfctaZOszPDTf4uPkSrrNbHTp2f0IbbH3+Gd1ftYvnWypYfThC6mYyMDJYuXcry5cspKCjgrrvuCh8bMGAAt99+Oz6fL+G5pmkmPVwxGGz+13V3IXHk3cDVD7/EC/6fUzX2HRqK9maAqrAP+OrAlRnTNxC0COqo79dAPW4L/I6ccJPpiAi2dtpCXqSqWGXFx4sPL7HdK4p4V8mOynoGY7Br4BwG7Hgv5tivd17Fz/6xg8nGd0y68Z/teVyhr7DwStjxdXKvOXAyHP3HNnefPXs2X331VXi/qKiIAw88kMcee4z/+Z//iet/6aWX8re//S3hsaa89957XHvtteTk5LB27Vrmzp3L3XffjWEYZGdn85Of/IS33nqLu+66iw0bNnDHHXfg8/mYNWsWd999N6Zp8sgjj3DzzTeTn5/P1KlTcbvtv91nn32W66+/HtM0ycvL44MPPmjzMydCRuTdwP6BJQBYXzxGrTfq27su3n1x59urGWlsD+8HgxZZupaAKyLkOjqnhDPiTx+/89W46yml+EBPxwjGV+RetnYTAygne9S+LJz5UNzxe1y3c5HjJeZc8wTTr3ySOl+g5QcVhG4kGAzy9ttvx6Wy/e1vf8utt96acKQ8fPhwDjroIP75z7YNTj7//HPuvPNOVqxYwbp163jhhRcAqK2tZdasWSxbtoz+/fvz9NNP8/HHH7N06VJM0+SJJ55g+/btXHfddXz88cd89NFHrFixInzdG264gddff51ly5bx0ksvdeJVsJEReTfgNTMhAP7aCo67dSHfhLS3vnw7GfnDYvoO/eAKBjv24HPkUBlwoIIN5KCxXEPDfQbkREbkKkrIm6PWzMXjt78clm+tZGdVA3PGDeDNt9/gApcmc/QB+DZFrvlucCpzzWXh/ffMi8CEte/Xstf8H3foNRB6Ie0YOSeT+vp6pk2bxtatW5kwYQLz58+POT5q1ChmzZrFv/71r4TnX3XVVZx44okce+yxrd5rv/32Y9SoUQCceeaZfPTRR5x66qmYpskpp5wCwNtvv82SJUvCCbzq6+sZMGAAixYtYs6cORQVFQFw+umns2bNGgAOPPBAzjvvPE477TROPvnkjr0QUciIvBswQm6NYMDHLc4Hwu2/e+CFuFSz33fYP7Gqc8ew2DEDZ7COXFUbjiEHGNE/i9Ij7yH4o7cxolwzvoOuSHh/r5mFM1DDprI6LrnrObY88XPmXvs4T7pusjvkj2DOzKkA+MceRx3xvnaAzZ8+R0VdxPeotWbZ5oqYPl9tLuet/y5v6eUQhE7R6CPfuHEjWusYH3kjv/vd77jlllvQCaKvxowZw7Rp03jmmWdavVfTjIqN+x6PB9O0XZlaa84991yWLl3K0qVLWb16NQsWLGjxuvfeey833ngjmzdvZp999qGsrHPBBSLk3UBWaJHOss0VHGBERO5vrnt44fHIhzB6Kb2JRcCRiduqJ4d6lCcv5ppFs8/CHDYTwxkRctfExCOMoCODHF3D9juP4DTHB5zreJMPHFGz53lDycvJht98i/OMfzL6gJMAqNj3MgJR/vq51qd88tg14f1n/ruJj+/7BYs+ez/c9vq9V3D4qwdC1bY2vTaC0FEyMzO54447+Mtf/kIgEOv2Gz9+PBMnTmw2X/nVV1/Nrbfe2uo9Pv/8c7777jssy+Lpp59OmJhr3rx5PPfcc+zatQuAPXv2sHHjRmbNmsX7779PWVkZfr+fZ599NnzOunXrmDVrFjfccANFRUVs3ry5PY8eR68S8p1VDSz8envrHbuZbMMOdzqSTylQNTHHztjwv+Ftb9To3GkqAo4ssnUdOaoeMzNWyBvZXB01oncmrtFpOWyxn8XXjHbtie/QOHmaPQAMg/FH/Qx+s5bso66llPyYrsfsvDe8/dXXy7jI8RIj3vxJuO0HjjftZ9n9XUJbBCGZTJ8+nSlTpvDkk0/GHbv66qvZsiXx+om9996bGTNmJDwWzb777svFF1/MhAkTGDlyJCeddFJcn4kTJ3LjjTdyxBFHMGXKFObPn8/27dsZNGgQCxYsYPbs2Rx44IFMmDAhfM7ll1/O5MmTmTRpEgcccABTp05tx1PH06t85L+560n+6b0U/4BFOIvHp9qcMG7VtknCen+QRilWY+YTXLEbQ9mjdEdmfsJz+hUWw8bQjiOxv9xrRAR+gFWasE8MSkF2EQ7Aq52QIF9/gz+Ia/0b4ISBwe3s3vothUPGUK0zGajKqd61Gfeo1m8lCO2lpiZ2MBQ96l6+PPKLd+rUqVhRK5ob48kbaZy4bInc3FxeeeWVVm04/fTTOf300+P6nX/++Zx//vlx7W25d3voVSPy42v/DYC1+vUUWxKLW8XOnteOOCxhvwZ/kHXWIKpdA8g8/CosZ1TseFZ+wnOOPOTAyE4zI/JyvzO8XRCMCLnPXQBX72jR9voE/vJPvljGw//5kOuckZn/JU/fzK7qBqqwR/+1ZYlHQoIgJJ+0E/JVO6rYVlEf1x60NKc5bF/tC6u93W1Wizi1P2Y/64zIgoR6FRHfBn+QDOVlz8CD7BWarqzwMXd2v4TX9jiiYsebEfL++ZGJ0qEqkhCrdOxZzZ7TiBUaju/IjCz3P+ClQ3CvsUMd6yadwxJrDEdWPc+yPx3NPsa3APgrtrZ4XUHoKXz99ddMmzYt5t+sWbOYM2dOwtF4TyTthPz/7ryc+r9Oj2uv8UbcF2duvQmC/rg+qcK0mqwyy+jHt4fbcdsZuj6c0KrGGyCLBlQoEsVnRkQ2oxn3TEzRCFd2wj7Hn3wO1blj4toNV8siDhEhH3jabbwy48Fw+171S9ntHEzmqXfhzbZDI+ebX4SP6yp7pL95T13MeyOkP4kiQdKZyZMnhyNOGv8tWrSo9RO7kPa+xmkn5L91PsVoYztU7wy37anxsm5nJTU64iOu2fxVotPbxNaKeq57/G0afMn5MjC1jzKjP6U6j11TfgbAmINO5dmCC+0OfjuqpbS8mjxVhyt3AABeIxKRYow5POG13Y6ot7CZ4rM5hUNx/iL+g2m6sxL0jsVq/Ig4PBxz9Inh9sGBrVRm207wGRc9En/tmu38d8Me7v3L1Sy845et3kdIDzweD2VlZb1OzHsSWmvKysrweFpfI9JI2k12erUDtwoQLN+ImVMMwIO3Xs4VPBYzKVe2+mOyS/bp0D3+9Mw73L7tLNa//CtGnXJdh2299fXVTB+ej8/nxfK4KbpmXazYhpbX46tlfRW8+tRdzHOCO9/ON37YQQfDBvAdcBmuzIKE9zCMtlUOT1TuzeFufUSuo15Uw+niyaJLObP0NsYYW1mXNcu+dnY/3gtOZU7UIqJRtV+y6MELuMn5LtQC3N0mO4WezdChQ9myZQulpW2YNBc6jMfjYejQoa13DJFWQq61poYM3FRTs3szecP3A+B0a2Hcbwtd2XEfbeHGV8EJ/be9A3RcyMd8dCkD1VbmmRvBT9yIWbtDrhBfDXc8/Cy3Oe8BICPfHpGP3Gs8XLYCV5OKQE3ZpfMj+VvagcOZeOFPNI2uFbTt/tGe/PAxZ16kwEUN8aOHMx1RGRfrKyAjP66PkF44nU5GjhyZajOEJqSVa8UbsKjR9iiydndEqBMlhLLqqzp8nwmGHZxf40g8Cm4rJ5qfsLexsdnjRkjIKyrKOa82MgHqyoiKGc8bEonzbobcK74meEXz92nkbk6L2c/KTTyBGk39oQvY4xkGAyYCsKYi8lpnFEQKXCjVSoHn+gTx64IgJIW0EvJab4AGXAB4K+yVg1rrmJ//jVSW72Zpk+XjbUFrTT52RR6zvmtLnjUK+aKvVzHNWBdp9+Q0d0pCPFm5mM3EmUczfJ7tky+dcwtVx9yNOfGEVs6AA+cdT8GVyyFk6xnHR1aP5vUfHN6eet7fqA59ye7JGRd3nTWP/EyKVQhCF5FWQl7nC+LBjgAJVtorOAOWJhj1GNV72RNy0yveIOuBAyhd/k677lHjDVCgbCHPbGg5xrolmk4GbRnzg7g+ZqNg71gWe8DV+iRkRzju4H1hQSVFc35K7n5nxxShaCvjx46jXNui7sotCrcPHTWe2wbYtUFNTw5bznqf9VMuY49pu4XGVn8G9eVJeApBEJqSdkKeqewY8b22vghWEF/AikRWAOakE1hk2as6xxhb4Zt/t/seudhRJK5AdYdt9QdjhdxVHB/+5wgJeWbV+tgDXSTkycIgtFrOHRvuqI3QwiPLz9Cx0xh18gJ8P4uKlkmQtlcQhM6TFCFXSj2slNqllOrStHd1vgCZROXVLl2NN2BFJuSAjMGT2DH+vPC+z92/Xfeo9wXxKHvU77HqwepY9Q9/MDaroZFg+bwz0xbC/r4mE7PNxIP3FMJzEq5YF9AZR821m2dHcq8MLCxk4ZjrAfjm4Yu6x0BB6GMka0T+KHBUkq7VLA111WSp6FWbms+/K8OBLba7Sk5EDRjPvBPOZmmuLSpWM9Xjm71HIOK+AcBX03znFgg0GZGbrgRC7rEFOyvYZGK2h4/Iw1+bTewcO3IELKgkY+bZMe2Zo2YDsHfd5+Dt+K8cQRASkxQh11p/AHR5WELJJ3aF+FXuSQCs3LSTfs98j1HGDjYPPpoBP7QXpmRn5+I/+WGCWqHbucLz3VWlePBRHUpfFajp2GP5mozIHY74SM9GIS+2dsUeaCVKJdWEXStt/MI5eNZ+WDok/w0djyYSBCEx3eYjV0pdqJRarJRa3NHFBF5th7hVYofnNbx8ObOMVQAE3blgRELgHIYigKNdQl5R52POOyeSrRrYkmGH25WtfL+Vs8AbCPLzvz3B76+5hD277RWngSa/BJwN8REw7gx75aZHNbGxmRWaPYWX3MfZG210ARmG4vnR9kRooE4mPAUh2XSbkGut79daz9Raz2wsfdRefH7b5VHrsJNATTfWho8ZTZI/OU0DkyBfrljV5usHLB2OIa/OGwtAsLZ14bn+gWe4q/IirjEfxbxnf/taTVwrnmnfjzvP43TGtaUDZ171EFxTBmbb15Op0GKg+vuOCOeWEQQhOaRV1ErQZ090+s34kaAjO3bxjsNUOJTF94wP23z9GPENLYkPtsGnu/+2x8LbeUHbFRPtWqnMGQO5g+POy3Cl1csfQal2iTiAM9deBZpDLRtW/pfvtu1q5QxBENpKWinJmlE/pEF5WOmcEHfMHUo01YgjOkY60CT7YDNER5pkFQwhoA2C3roO2VpTH3GX5FV/m7CP29FkNeSv18Avv+zQ/Xo6rv4jwtsZz5zGyPvHUFMlbhZBSAbJCj98EvgUGKeU2qKU+lEyrtuUE4/7Hp7rdjLt4OPx61gRzOxXHLPviEom9cgTj7Fh3epWrx89is4tHEw9bjZu28Fbzz+A9jUv6H7il6ev3xgpdeY76aGE5xXnNolkySmGgt5ZVufIGWP4wm1XGS8O5YWpfeyMFFokCL2HZEWtnKm1HqS1dmqth2qtEytXkpgzbSzmdWW8Py5S7zKjcERMH4cZEfLzv/sNRU8krsoTjT9ohYsNB0cdRo6q59CKf3P417+h6t3bmz3PmSAdrBUqPlx/0mO4pp6a8DyXw2D1OYtbtas3YBiKnQfdGNOWW70mRdYIQu8irVwr0RiG4tAzL2f14O/ZDfmxQu40Yx8ty2o9HjwQ1PYofOx5DCvM5YPg5PAxX0Nts+eZ2k+F2Z/1ehClriG8++7rmOUbbDsyWgnRyx7Y8vFehCszN2Z/V+ZeKbJEEHoXaZXGNhHjLngAyn4LTVK9Ng3gq3fk0Vr2bV/QwkUATBemodjv2vfhJnvSs6UiN6blI+DMYJUxkX19i5n7fiTLoKOV4g05HvstqHEW0rPXc3aejOy8mH2ntzJFlghC7yLthRyHC4onxjU3LbjgdWS3KuT+gIWDAIZphwVGV9/xe5sfkTu0n6DhJIAHt7+hycGWq3wMzs9gx/8sY0BB6yll052iqNqhq4zRFAVEyAUhGaSta6U1CrPd/LX4lvB+sIXvrGWr1rD6s1fx+wOYSqMcdqpcFbUwR9c3LzoO7cMyXATNDDJ0k8LPzszEJ0UxcEgJRkZeq/3SnUH5ka/S71zjyAjIKk9BSAa9VsgB9jlofng7mCCyJMy/Tmfca2dhhfKqNAo5wDsD7QAc1YIbwKH9WIYLy5GBUzVJsuVse9293k6228GqUeezp+QY6lyFZOq6HlUkWxDSlV4t5BlZkVFuS2sJhyt7cYqqtFd1mlHie+iFf2GJNQbDm3j0GAhauPCjTRfakcB504YReV9i/A9vo+C8J7EaS8Y1iHtFEDpLrxbynIzIyNq0ml8UtEeH0rHutLPwNtbMBDANRZ3KxuFPvMLTFxJyy3SjXbGibWFAZsv1NvssGaE5ASk2IQidplcLeZYr4hd3tCDkNaFpUFVml1vL7hcbElhnZDKkbiVLPngl7lyv38JNAG26MN2x+bl9ZlaHqvD0BYzGFAi1UmxCEDpLr1aZguzIiNwVbD7qpLEOqLNyAwBmTuxyf2/Adszs805snm2IjMi16cZVMCTmmDbSPyioq3Bm2wU/9uzeyZprJ7LpHxem2CJBSF96tZBnux3oH73Fp9nzydK1BJrJZOjVdrhhXr3tIycrNjvjCLUzvK399THHfIFI7PnAktgcMCLkzePOtYV845YtjDW2Mnz90ym2SBDSl14t5ABq2L5U5NkCW/7Rgwn7NI7IBwbtZfVNFxc1ViACqF0Tm5/cG7BwKz84PJSMGkuljvKTG+mZprY7GDpkBEGtqNu0rPXOgiC0SK8XcoD8/ezkTF5/4lC3RiHPVyH3ixkrwMbsSK3JQG1FzDFvIIgLP8rhwuM08RJx56gx8zpreq9lQslgluuR5NdEcso3+DtWH1UQ+jp9Qsjd+QOxtCJQnzjyxGilIM+Eo3/Ka4ctBCI50RtpdK0ohxuPwyAQeklrRx5Jxgl/7bzxvRTDUFQY/XDVR/KSb7zlgBRaJAjpS58Q8twMFzVkYNUnjgV3G61XrDFdoRqeIR/5k6+9x9LfH4xVU2qPyJ1uHKZBMJRe1zv6KDt9gNAs9Y48xocqMgGMC6xiz87NLZwhCEIi+oSQ53icVJGJbmbxiakjP+nrxp2UsI/DZRdE3rpzN/95+EaGf/w7pgW/wrPtUxzKwgjlVDFDKzvdTTL9CfHUqviEYgX3TIr71SMIQsv0CSHP9Tip1hkYzZRtM6MmMz37nZewj8NtT2LOWHUrx2z6Mwea3wBQ77f9Miq0GjQbW4QyC/pOetqOUuqNfPwqj76Lz9UUAPYsfi5VJglCWtInhNzjNKghE8Of2LViRI3IjazEKzFNpzthezA0yjdCx6uUnYxWZQ1I2F+IEL1Iy+nOJHCqXfu0vmwL5bU+/v3Ck9SX72zudEEQQvQJIVdKUW9k4fTHF5dYv6uag42vIg39RsT1AajyJmwmGJpAbRT6fj9+kYb9L4X+oztlc18gg4iQu50O+hcU0qCdeCu28/C//8NJX/2UxY9dwTMvvwxat3AlQejb9AkhB2gws3EF4oX8gXv/Et6unnIBNFlm30hJUeICEVZDo5DbrpWsoXvjOep6MFrItigA4CRSrcM0TUYPyGY9QzB3Lce9ZxUAB1e8yGlLzmH7+11aPVAQ0po+s/QwYHhwWLHD6kDQ4mbrb/b2SQ+SM/X7zZ4/fmDiyUsV8rubrsSuF6F5nCq67JLCYRpscYxgWt1qvhd4IKbMk3fzF91unyCkC31mRB40XDh1bOKsWm/EN+4oar1+5FOBOXFtKpQV0eGSdLXtZcrMQyI7xXsD4HXm4glWU0RFTN/m0isIgtCHRuRB043DFyvk1V4/4YzlReNbvUbjys+NxjBGWHa8c27DdgCcLikg0V5GH38FzDoOBk4KtwVceeQ21MaMxpdbJeTUl6bAQkFID/rMiFwbLpzaHzNpVusNUq0z2DloLjhbq+gJxcoeFRaedDNrCu3qQ5PqFgHgECFvP4YRI+IAztxItM+O6ZfBzz+nQuWTVbMRgi1UwBaEPkyfEXLLdGNg4S2N5Pao8fpx4cfbb2ybruErskUna+T+BE96IOaY0Ux4otA+nCMjy/QdpoKicdRbBoXBXWx74qcptEwQei59Rsg3Vdn+cNfd+4bbamprcasApqdtqzBn/fQ+uHgxZBcxuCA79qApQp4MGgtOADgtOx2Cwv4VNXj9symxSRB6On1GyJXf9m8rNIGgRSBo4a21F/M427qc3umBwjEA5GU0SVGbIys5k4E7KxL+6QhVWo3JaVa3p3sNEoQ0oM8I+fS8SIWgu265gvduOQV/KCWtMzOvmbNa5gXnsZGd3MGdMU8IEZ2jptFdZUV9TD/+4/Esef2JbrdLEHoyfUbI9z/3DwDs8pRwie8BDve9g6rcBIA7O79D19yqBtn/Dz8BVCu5cIU2kZURmXTOmHclAMGMiLvlQGM5+3x6Ebf/73m8fNdvut0+QeiJ9Bkhdw/YizfMQzCCUSGIu+zVg55+Q5o5q2V8yh4xmqLhSaMgKyr1r8teTXvAj/5CadH+Mf0ucfyb40sfYE+tDy3L94U+Tp8RcgDlq6XQvy28n12+EgBj0JQOXc+v7DB8U4mQJIvC7PhJ49ziERT9/PWE/T/747F88vydeJtUbhKEvkSfEvKJxoaY/YxABV7l7nABiECoiIQIefJwOZr/SH6xz818x9CYtmPMzzlw+TW4/zwC6iu62DpB6Jn0KSEP6tjHzQ5W4jVaXwjUHPMmFNvXKR7VKbuEJvz0I7ggfgQ+4/iLWLz/nc2f11DRdTYJQg+mzyzRB/A3edwJwdXsdnY82mT2seeiBxm49jm3s6YJ0Qyc3OyhU+YfSmndT3Dvdz65D8b6zQmV4ROEvkafEnIrwQ8QJ/6OX9CZgZp1YScsEtqLYZoUnfynhBOc2luDzDsLfZE+5VppKBgX1xY0ZEVmOqKU4tvio2Pa/PWJS/n1ZDburub5239NfdmmVJsipDFJEXKl1FFKqdVKqbVKqSuTcc2uwHvMHfGNZp/6UdKrGPOzp3glGHGvlH/2eAqt6RgPPfk0p5Q/SM2LEhMvdJxOC7lSygTuAo4GJgJnKqUmdva6XYEjI776jzJEyNOZASqSp7x4/fNpFblS1eAne4edPbNo8+vsWbuIQNDixWceoXzzyhRbJ6QTyRiR7wes1Vqv11r7gKeAE5Nw3aTjMuMf1zCdCXoK6YKr6RxHXVlqDOkAD7y+hCucz4T3M545kyUb9vC9FZfS76H9WzhTEGJJhpAPATZH7W8JtcWglLpQKbVYKbW4tDQ1RQJyPPGjb9PZsRhyoWfQf/jeMfvBmt0psqT9FFSvjtk3LD8b3rovRdYI6Uy3TXZqre/XWs/UWs8sKirqrtvGMKwgk0VjLuPDAWeF25yDJrVwhtDTGfaDe/l4dkT8GqrbJuRv//H7lP5ldleZ1SYKqtfE7JuWlyHbXkuRNUI6kwwh3woMi9ofGmrrkcw6ewHe/S8J77uP/WMKrRE6jTub6XNPDe8GvG2LJZ/X8AZF1Su6yqo24areRK3KYv1ZnwCw3T2SQTrya3XLt8tSZZqQZiRDyP8LjFFKjVRKuYAzgJeScN0uw6ej/OJtLCoh9FwyXQ4WT7oGgKDfm2Jr2o4V8BE0nIwauzfvMpNh9asYbWynTPUHYOgTh/DN4vdTbKWQDnRayLXWAeBi4HVgJfCM1vqbzl63K/EpmeDsbZQNOhiAoK8h3PavJx+FBXnhLJeNxCwmsqzuMC8hygoQDCVeqwxG5mrKSyLx8Xu/cgLepVIZSWiZpPjItdb/0VqP1VqP1lrflIxrdiXKMFNtgpBkTIdd/DoYiKQpdq94DoCG9R/H9PUHo4TcV9P1xjWDoQNYISGv1VF52PsV87IrIub+rV91u21CetGnVnY2cszkQak2QUgyDleomlBoRL6ptJr5xhIAKut8MX19wcgofP2rf+kmC+MxtD8s5PXKE253mgp18K/C+9n/vQNds6vb7RPShz4p5E7TgBPvhp99kmpThCRhumwhtAK2kD/+8F/JVXUANJRvi+nrC0SEfNTXt3WPgQkwrCBWaEFaQ5SQu6s2M3xEbEbN3fce1622CelFnxRyAKafDcV7t95PSAucISH3++zRt5tg+FigcntM32ghTyWmDqBD8zXBqD/F7IN+wpThhWw5/J5wW1HN6rjzBaGRvivkQq/Cwp73GPjVXbz1n+f5df3tAAS0gVEZm5DKGwjGnhvoRAbMTmDoAJYRmngP/b976s8wh+0DwNCDzmLDXj+InFC1reklBAEQIRd6CaOL7Tw6GXjRn94Vbv/IdQAFNbELb+p9Aep1JEpk2z9+1D1GNsEkgG7M9ZNphxw6amN/PZSc83de2vefAGx/5AcIQiJEyIVeQXFuxMe8R0eSo+0yB5IXLCforQ23bd+1mwzl45NCeyFRZuXa7jM0RNDSOKOE/ORzfs6mjAlkHfbruL6TZx4EwKDyxQRrdvPGs/ez7hHJgy9EECEXeg0vu46mysgnK8MW9Z1HP0R9TSUAu/5pj7pXfLOUmi3LASiZcjArrBHUugq73VZ/0MJBEB1yqQwbPIjhv/0M5+D4QuAjiwt4cpztKtry+u0c8c3ljN74NCsW3kdD2ea4/kLfQ4Rc6DUEHJl4dB0Oq4Ey5yCKZ52KA3tis2DXIjburmHis4dy/H9/CEBuXn/26GxU9Q5ev+0nVG/uvnVsvpCQ08Y0yvscdgoAI76O5NSfuOgKPHdKriBBhFzoRQQdWbi0D49Vi9+wR+UKe/GPaTWwbn2sCyUjM4sqlcvQhtUcWfEUwad/2G22+gMWToLhSc7WiHYdCUJTRMiFXoPlyAIgT1cRNG3hc4TCEB2BOqpLY90QpjuLGjMvvJ9f032+cn9Q48aH5WhbqcG8DCdP9vtJwmNNwyuFvocIudBrsFzZAPTX5QRCQu4fOTd8PHvX4tgTnBnUNI08DHZPKKI/aOEigDbbXjP20HOvx6/j00t89+C5aF9tgjOEvoIIudB7cNkj8kGUEXDZI+1TfvhL3g/aE4hG+frY/qaLycf+lB2OwZG2hspWb7N5+SfUrv2oU6b6ghZu5Yc2jsgB+me7qMcOm6w57j6qL1nDB0xnTPUi9vz3uU7ZI6Q3IuRCr0F57LBDpwqiMgsA8DhNvhxvh/TNrWqSXVlb7Dt7LgP/dyVPD7PT4LZW81NrzbDnjibr8WM7Zas/aOHGB2bbfd9uh8kyazQAmVnZ5PQrxnnmEwBUrXynU/YI6Y0IudBrMNxZ4W1HVkF4253dL6bfu8FpbDUGQ9G4cJvKtPsEalouQ1jnC7Z4vK34Axo3fnC0bxKz6oArqTD6YQybBcCYIYWsswYxcsuLULcnKbbpYCAp1xG6DxFyoddgRhUJMTyRRUHnH3NQTL+5C95iyLUrISqdccEoe1n81q9bLuSwp9bX4vG24gsE8Sg/ytl21wrAsUcfT/61GyDbLpdYmO1m6cQrAPBu/qJTNr320AJYkEfZ70ezaeFfO3UtoXsRIRd6DaYnO7ytHJEl+B6nycLgvlEd40P+9ho9hlKdh9WkCEVTymvaVkquNQL+hpCd7RPyRHgGTwCgcufGZvt88eViNnz6QrPHv/70DY7a/DcACqkgb+n9nbZL6D5EyIVegzMzakTeRCCrdWaL5w7K97BZF2FWt1xutrKqIrITXWmoHWitCXrtFLvKldFK79bJyh8AwIB3fpXw+LJlXzDj/+ZR8vr5+LbG1wHVWjPytdg8Lj7dtoVKQs9AhFzoNbgyIu4Uo4nLolbZQr4+Y3LCc90Ok2qVg8NXhT9oUbNnR8J+NVVRUS3BjrlZLv/9jfR/5kR7x9Ov5c5tIGBG5gbWffYKC599gEBNxF++4oU/hLd3f/VW3PlVDQF26ogdm9UgsvzJ8bcL3YMIudBr8MSMyF0xx2pCQu4cFesvj6bBzMIVqOaxB24j+45x6C2L4/rU1lRFdgIdK/R8q3Ur44wtAOQXDuzQNaLZb3R/dul8AHIXXsTR3/yGbQv/jM/bwLLbTuFM9Wa4r78yPhVuRZ0Pt/KzYeiJsKCSz3KPIlPXsuUvB7cpHFNIPSLkQq8h0xPxfZtNRuQB7GNO1XxRCa+ZgztQgxUScPXgPHw7VsT00b66yE4HR+TR5PQr7vQ1cj1Oqi/+hnKdTZGyhTdQsZl/P/xHplbYI/AV/Y9gozUAqzzej15R5yefGoxQ5I6VZds0tPorgpvjv8x6MpXVtZRvW5dqM7odEXKh15Dtjvh1G0u/RRrsY07d/Cja58oj06qmioirou75X8T0UcGo80Nl5TqFMzk5VIYXZMak7x219WWWb6sO74+ddy6rXRMZuPNDqN0dc25lVRXZqgEzFAnjLBwZPrb1u5V8+tq/Ovzro7t54e9X0O/+GZSu/pTS1Z+l2pxuQ4Rc6DVEC7mjyYh89tE/IICJZ1LztS8DOUMwsRjjjMSSB4ldEm9ZUXHkyRC3NibNag2nafD5tJti2mYX278+vp11M44Jx1I7/UIyaKB82asx/RrK7QleZz97hetBc4/lM9dsAIZ/cjWzP/sZpR8/1uL9A0GLlW88gm4lDr+rGV1nT+YWPXkURU8eGfel1VsRIRd6DdmeqBG5FZszZf/99sdxXRlZE+Y3e77Rzx6JnqjfDbfVGLmxnYJRQp4E10qiUMiOcubJp8CCSh4fdgMAx+x+GIAxh/0AlKLfMDtMsa48NslWoMIW8oyCoQAM6JfDrKsW8h4zw31aynv+1YoVbLh+byZ8cimVD56QtOdpL1prxobmHhrxbV6SImu6FxFyodeQ5YoS8pwB8R2Uavn84tjK9cutElRT94mOWvWYlBF58sP8rOwmfnen7SrKyc3Hp00CNWUxh2t32+KX2X9ouE0pxbZ+kdj7YGXisMzSimqmPDObvQx7EjW/YgWkaGXopi/eYKAqj2mr3tU3Cm+IkAu9BtNQPNb/Mt7sdzrOvQ5t9/n9h4wOb1e4BlGHGxWIXQCkrZ47Im/E3W9wbINh/5n3y3IRwMGIlfeHc8rs2LaJvTc9bpuSNyjmtFmn/orPJl7NF3osWdsXJbzXP/79Snzj7/tT+ftRWLu7d9LxtXffi2ur7yMVlETIhV7Fub9YwPxLOrYqcUj/iBsl79JP8eJG+2pY9913ANT5AtRviiyDt/xJmOzsghF5wcDhCdv7ZbrIVPaviOrP/4E3EKTs3uOYaH1rd3DnxfQfPWQA+592BZs848luJq482x/xQX/zg6/C23nBMsqWNL+StCvId9hfrK+MvYlNlj1xG2jml0RvQ4RcEEIMzs/gtYKz2TDjSlRmP3yGh+H1qxj92DQo38A9Dz3IebWPhPtv3vRd52/aBUI+bEBBwvbcjMjoP+fda/j0xvnsbUSFIxqJ5cDvyiND1yV0meQatnh+O/lX7D16BE/l/Th8rOjTG5OWyKspO/5zC/WLHo1pMyzbluNO/ykFV69ihTUCqvpG0Q0RckEIYRqKo355NyUnXAUQLhcH8NLCV/nhjj/E9Le2ftnue1hWk2X9XeBaGV6QOB2BacTOEcyhbROBwdBI3b8xPpxP+WsAGDP/QgBqnP1jO1Rsitn1+nyUfvEyWM3H87dGWY2XgZ//gYyFl8TaEvRjocAwyXY7MAlSsucjqhc/w8fvv8b6l//c4Xv2dETIBaEZKnQkCdegVY+GF9uE8VbRXur8TdLgJin8MJpMl4N357+a8NjjtD+Pur9wbwCc/ziWulVvxxwzQkLeWNRj+lHn8V7R2bycewYAvupIOOL2PVXsunEiRS+dQ/V/H2+3HY1s3lOXsN2wfASUMzypXYX9hVb38d1Meud8Ri25kYbVbyc8N90RIReEZvgua0p4O4/4UmpGB4R8d3WTSJcuGJEDzD3wIL496glqz345pv2Yyx9ljTWkXdc68/tn8GpwPwDKPn/abvTVsnZHBTN3h4p1hIR8n70GM+fnd8PUswD48OVH+e9dF6ArNvH4w3cwzLCFPWfhL8DqWG73sj1RseFRI3sV9NtCHqLhew8BUFz+JXnKFv89qz7s0D17OiLkgtAcWYXhTRex/uFKnYnpq256RquU1Xop1VGx6UZ8Dc5kMWb/48gac0hMW16Gk7FG+yYAHabB3pe8yEprGFbVTrbsqYU/DGave0cwytjBFmdJ3HNkFtg5ZObVvMK+pc9Td+/h5Pp2xfQp+/ChNtvw1ZYKqhvstQG+2qhfRqGoIt1QRb5VRkBFcuwcPGMKfwicE3OdwmX3tFoFKh0RIReEZoge3ZUYO2OOlescHP72j8hrvUG7MlCKaOonbysj+mdSSgGu+p383yexqXC9h14d1z8vvzCmUHRWw06m+L6gjgwuD14EQO2utoUnBi1N7X1Hs/kvdkipv6EmctBXh9aaPTdPZG7gY4IqdvJ4zhmX8X7R2Wy/aC312oXLaqDy8R+26b7JJLhzFdSXt96xg4iQC0IzeIrHNnusQuXg9Ld/RG5pjZvUllJ7IjAvZv/N4AzezGzZd66UotrZnwxvKVl1sZEgo8dMiutflOvBqWJdJ7P5mm3Fczj/Z1dRrrPRDW37IvQFLGabK5jo/wYAyxsV2++vY2tFPf2V/V4EjdislwdM2otDf343AwoLyVB2VIt7xxeU7dxEw/aWi4gki7W7ajDvmUXN3fNa79xBRMgFoRl+efws3jljDbdY58QdqzNz6e/dTM2Ote26pmVZuFXqRuQAO/f7LausYeH9CT+6jwMu+Uer59V7BpAT2MOk5X+MPeCML44xrF8mNdqO+ikn4kpyFI4k2+2gFg/+6rblQfEFoiJctCboi5qvqN/DrqpIPL/VzOSxaSgeH/Ab24ZgHf3vmYznvlk0VOzAKu/aRUNLN9krabOru26BlAi5IDSD22Fy2PhiApnxy/3rTFucsu/dp13XtAKpFXGAS47bj4xLIis1hxbmk+VuPZ49kFmMicVMY03sAVdWXF/DUPxtiF33szpnr3B7VvEostwmQ9Vu9tr1BlRubXXS0xuIOu6twvJGhLxh9wb2bN8Q3reajMijOeeia/jX0GtwELme57ZxGLfH/6JIJk5/TeudOkmnhFwp9X2l1DdKKUspNbP1MwQh/QgYdibFbTqy0Ga3o2MFIXTQFvIduh83mT/tvHEdwDQUI/pn8dTkB1ieewhk9m/9JIDcSLTLdhX15ZZgRA7wy3NO46W9fk/+92/ntkG3sM4aRP74Q8n2ONhohc7/20TqPvh7i7f1Ro3Iv3zjn3x/5S/D+/Xv/gXnq5F48qDZclrgxpzrcTTn5vHXdy6nTvkGnL6uL87R2RH5cuBk4IMk2CIIPRKt7Ek7z9BpBLT9JzP84LM7di3L9o9/VnwWZ//s2uQY2EHOOOU0Jv3q5TZHzrgKIu6Y+nEn82lwor3jSCzkeZlOTjjnl+QOn8L/nPdjCq/8GueAsbgdJs8Ovybcr2Hlay3e1xeMCPmoJbGpevuVf00gKtVwjjc2MiaOJmkIwjRZuASwZtM29vxhPLvvmNuh+qxvvfcO3D6Vkm/uijR2sM5ra3RKyLXWK7XWq5NljCD0TOxID4cB9dij8wOmTeJV8zDKHUXtupIOuVYOGFtMSWG8S6In48rOD287C4biOOdplh33n3DRjpbIcjvIy4z4r0cNi4zuo0fcifAFrLC/PUD8l05/VYWl7fco15e41moj66oiQnrHyHtZGLQzPNY+cjK6OjYyad0nL1KgKyis+gbK2u/f/vST9wEYWvZxuK3uTxMgmHz3Wrf5yJVSFyqlFiulFpeWpjb5vCC0h+gUJG9b00ONDvxmBi6rfYmzdChPumqD+PU0HBmRScuMgePYd9xwps48sEPXcmZH3FRGfVkLPW2hd4VCNhujUwAeLrgMgAlqIx+a+7XpvgVDxgPwsfMAfnnumQSOspftZ3l3UvVC7JL/zG9fCm9XrWm/08EI1TsNRg3CM+u3d0mxi1aFXCn1llJqeYJ/J7bnRlrr+7XWM7XWM4uK2jeKEYRUUhsqLuHNHkr2affz2txXwJNL0Mxst5B/vs4exKguWJrf1bg8kVJyBRMP69S1fK58doYKRhfXfYvVpDZqNH5vPa4moYzLC+bjCaXrdasAZt5gvNrBp4N+0OJ9fzxvb77+8SYOvHohAIXFwwiGRvOuTR+FV4rurGpgbGA1/3XblZJqy3eyevUKNjz7uzbnicm17Lhx1XQytz75icRaFXKt9eFa60kJ/v1f0q0RhB7IccedxOXqV2Qc+wcOnzyMow49GICgw4MTf7sKKeSseBIA1UVL87sST2YkGZfh6NwvimOnDefNo95jQf9bAdj1ZYK85iG2b4iN927AzYSLn8WRGymgMTa7nn8f+yXTL7i9xfs6TYPJQyN+8n1KCnhmyoP803EKGcFqyj+zwzBXrtvAILUH/9D98Wonwdo9jHtyNiXf3MWO9+6DQMu56N9YtJRfOF4EIJ/YiVRd1/IvkI4g4YeC0AoHjyniz9ddR3Z2Tky75Qj5uP3xeVia4zLn84C9wCbdyHQn78vH4zQ5Z/ZIDj/yRCytCNQ3vzioaXEIr5mJaSg8+ZHIIafVwBn7DcfjbF/KA5fD4MxTTsWY8n0A+r1hu1dq99iLnvKKh1NBFrVbvg6fM/CDK6l+7ufh/UDFNvS3b8Vct+6Vq5q9Z20w+V/inQ0/PEkptQWYDbyqlHo9OWYJQs9HN4bd+RJn42sJg44ljEolg/M8bLQGUOMsbL1zG8nJcKGBwV/9nYqqxGKufXYcdpW2fxH4TPt/T04klNDo5JxDnTsqnDLgxVdlT3wOHDSMpdZejKv6NKa/c90btm1aE7htKuqJU8KTmFprvmd+kvA+v/BdzO78KQmPdYbORq38W2s9VGvt1loXa62PTJZhgtDT0c7GEbkt5L66KqzrC2Bl826CRgydfkI+INdD8VXLyLpiedKumeV2YCqNgSb/r8Ogoskqy6CfAVUrAdiM7UoJNAp5ZmTyNeBpYyx8MwwZFFXmrr4cY7udT6b/0DEsd8ULbyCUV359aQ0eQm6Wajti5pNVkWe4d0Yk++QTh7zLy9YBlNUmoURgE8S1IggdpVHI75wBDVX889V3MXSQujduaPXUdBRyAE9GJqqZBUAdIbvpitLS2GjmV++9ksNKbb91uccuDu0PubSyMtzhfttmdS4m/+jJg1jgtpfw79yxhRN33W0f6FfCDhXxxX957hruM88gO1gJ/gY2bVwfuUiVXYC6crct6JusImZMjqwanTzWLu5dVZ/G4YeC0NuosCKrCPWXj7Npt+0aaIxpbol0FfJkU5Tj5plApFC2vz52FWQgKpplh2GPmlWoPF70NMOkUe3Lsd4UpRSjR9i1Tj//LDZnuTNq5D99ZDGewhJ7p2or1RsiNVyrHvoeD99xPYGQq80x/1qG9svgeO+NvDp3IXsPzmPtTUczd3x8yofOIkIuCB1kwn6Hh7fV61dx/c6L7e02nKtEyAE7XcARVz3L46GMjA3lsbnSG/3iADtrbJdEQ4EdCz4kP4MLfZfx8v5PJWXy2Oxvj5hHVdl5aD6ZYq8idQ2PzT6i+tmC71/5H0745tJwe66q44I9f8VZa/vX83JyGJyfwfO//znHHnoApqFwmF0juSLkgtBB5k5KXK3e0pqaVe+2GKKWjpOdXUV+lptlU67Fqx00lMUKucewX6f7xz3I+4HJAAyZcwEAxbkeblvwvxx35FFJsWPkaPsLYu9SO8Z8n6lTAbjyxH0oafgXV062R+qZI2ez2SrC+db/JrxOTpWdVMzptl1QLkfXy6wIuSB0gt/4fxLXllO5muynvkf1y1fGHavVIb/ugIldbVpaccHBo9ihC/Dt2RjTnmv62O0ayoVnfp+f/PAH/GLM22SOiGSczHQ5khbKObwwO2bfHRqJe5wmG/54LH88xZ70PHnfkXzN6Ji+TwbmhrenfmvnVnG4Wk7glUxEyAWhEzQMan5puN4RH93xhmWLg95rfpfZlI6U9M9inR5MwY5PwBtZhu+yGgiY9sh23oRi7jy765KsDsz1cKTXzrX+JROazepoGIpKlRvTdjffD2/nKLvwhZHESeHWECEXhE5w5NSSZo8l8oM7CLLOGtThkmu9lQyXSYVZQEagEt9T5wJ2PLZH1xNwZLZydnIwDcVrf/gptx3wGVk/bXlJTE0wEm1To7K54qQD4js53PFtXYQIuSB0AqOFn885uxaDL3bVp4FFEAMzDVd2djXv+2wfteu7twE7WVY2dQScOS2dllSUUlx6xATGDmwm3W2IddrO8/LioMvY9MPPyM5OkMnSIa4VQUgLDGcro8VdK2N2HVgEMTFkRB7H1KP/hwcCx9g7DVXU+4LkUkfQldvyiSlg1imXcn/JXznhx9cwceQwDhlTxPnFz8V28rT8ZZBMRMgFoROYrpb9oL5tsX5ykyCWal8+kL7CBQePQg8JTWRWbqGuajcjjF1xmQ97AifNGMaF5/0Iw7TfS9NQXHXy/rGdspMfL94cIuSC0Ak8roiv1KsdXOz/Zcxx139ic1x7TE1eVvdNgqUbjjzbZUH1dt7/8D2A8GRnT8dpGtziP4O6xsikNlZeSgYi5ILQCaYPzw9vv3v4qxw07/gW+5sE0Ur+7JrDbFxsU7qOL9bYOUs2jDojlSa1mWH9Mtg48UImeh+hpOFf3Xpv+UQJQifI8URSkh41czx5RcNijteo2NhkUwexVPpVB+oucgaMoFa7cb5+OXMG23neD500upWzegYO0+Dus/ehpH8mx00Z1PoJybx3t95NEHoz7lz2GRGJVHgueAhzHd8QLeUKK1zMWYhn4pA8spRdtf7wLX8HwPB0X9RKMnjv8rmtd0oyMiIXhE7yG/9P+CQ4EQyD3IzICL1Ge/AYsZnuTB0UIW+BrKg5B48VyvPuTi8hTwUyIheETvK6Yx7L8o7lTcAdlVcjIyMTZ8Ab3l+5vQqDILobJ8HSDbczdmxpoTBcCWK0hRhEyAWhkyy97ojwtlKKC32XMV5tptht4tA+0BqU4pR7PuEZLILyZ9csbkfsl1yDyiBTFk+1irhWBKGTmIaKWXL/hrUvdwRPxjI9GGgI2lkQfQFLolZawd00U6C8Vm1CXiVBSDJ3nz2DF39+IJYZiicONAB2eltTJjtbxNUkX7e8Vm1DhFwQkswxkwcxbVh+uCQZdXsAGM8GxhpbGVC7JoXW9WwMQ3Gt/1zqtQuAoJH8ivO9ERFyQegidrpH2huhOpRzjKUA9PNuSZFF6cE/gkfyv367eIRluFJsTXogQi4IXcQHW+wFLfW1FQBY8ufWZnyhCWFtipC3BflkCUIXMWeCnTdk9aev8ukDlxKUP7c2sfTa+YweVADIiLytSByUIHQRk4YVwLcwrfQlAL5UJ6TYovQgP9OF1egb78biDOmMDBEEoYtQTdwCOkV2pCPeoC1N2pEemQ9TjQi5IHQRyoz9wWtipciS9MOw7BWx2imrOtuCCLkgdBHKETsid9LzCiT0VJxBu4Axsjy/TYiQC0IXoZrEQJsi5G1mrRoBQPXo41JsSXogQi4IXYThiBVyGZG3nXVqBOMaHsU75thUm5IWiJALQhdhmLFC7sJOaVvmGZEKc9IKv2XhxYXTFIlqC/IqCUIX4WgiQhnKTp710rhbUmFOWuEP2hPDTlMyH7YFEXJB6CIMI1aEMrAjMXxmZirMSSuuPW5vBuZ6GJjnab2zIAuCBKGrcDQR8syQkGsZP7XK/InFzJ9YnGoz0gb5RAlCF2E0KYiQoULpbCXHtpBk5BMlCF2Ew1T4dCSfdpGqtDek1JuQZDol5EqpPyulVimlvlJK/VsplZ8kuwQh7TGUYq0eGt4fosoAca0Iyaezn6g3gUla6ynAGuCqzpskCL0DQ8H5vsv5g//MmHZLqt4ISaZTQq61fkNrHQjtfgYMbam/IPQl6n1BdlLA/cHjsHTEXz68MDuFVgm9kWT+xrsAWNjcQaXUhUqpxUqpxaWlpUm8rSD0TGp9jSs5VbhQAsAJ04alxiCh19KqkCul3lJKLU/w78SoPlcDAeCJ5q6jtb5faz1Taz2zqKgoOdYLQg9m+vD88LY/SsiVIVG/QnJp9ROltT68peNKqfOA44B5WmtJuSwIIQqz3YwfmMOqHdWx1YEkakVIMp2NWjkKuAI4QWtdlxyTBKH38MovDuLh82YSwBbvj4J7i5ALSaezPvK/AznAm0qppUqpe5NgkyD0GhymQV6GMzwi/1ZLPICQfDrlrNNa75UsQwSht+IyzfCI3Iuzld6C0H5kZYIgdDFKQT9qANit81JsjdAbESEXhC7GNBSZyk6YtUZcK0IXIEIuCF2MGZUFsU67U2iJ0FsRIReELiY6C6JPfORCFyBCLghdTHRacpnsFLoCEXJB6GKiXSsXHDo+hZYIvRURckHoYqJdK5bpSqElQm9FhFwQupjo2p0Op9SgFJKPCLkgdDFm1Ij8pP1Gp9ASobciQi4IXYwR9VfmcEsuciH5SD5NQehiTKW41n8uA1QFF5vyJyckH/lUCUIXYyjFP4JHAnBxim0ReifiWhGELiZ6slMQugIRckHoYkwRcqGLESEXhC4mOmpFELoCEXJB6GJEx4WuRoRcELoYca0IXY0IuSB0MeJaEboaEXJB6GIkakXoakTIBUEQ0hwRckEQhDRHhFwQBCHNkSX6gtANLDh+IjNLClJthtBLESEXhG7gvANHptoEoRcjrhVBEIQ0R4RcEAQhzREhFwRBSHNEyAVBENIcEXJBEIQ0R4RcEAQhzREhFwRBSHNEyAVBENIcpbXu/psqVQps7ODphcDuJJqTCuQZegbyDD0DeYa2M0JrXdS0MSVC3hmUUou11jNTbUdnkGfoGcgz9AzkGTqPuFYEQRDSHBFyQRCENCcdhfz+VBuQBOQZegbyDD0DeYZOknY+ckEQBCGWdByRC4IgCFGIkAuCIKQ5aSPkSqmjlFKrlVJrlVJXptqe5lBKDVNKvauUWqGU+kYpdUmovUAp9aZS6tvQ//1C7UopdUfoub5SSs1I7RNEUEqZSqkvlVKvhPZHKqUWhWx9WinlCrW7Q/trQ8dLUmp4CKVUvlLqOaXUKqXUSqXU7HR7H5RSl4U+R8uVUk8qpTzp8D4opR5WSu1SSi2Pamv3a6+UOjfU/1ul1Lk94Bn+HPo8faWU+rdSKj/q2FWhZ1itlDoyqr3rtUtr3eP/ASawDhgFuIBlwMRU29WMrYOAGaHtHGANMBH4E3BlqP1K4JbQ9jHAQkAB+wOLUv0MUc/yK+BfwCuh/WeAM0Lb9wI/C21fBNwb2j4DeDrVtodseQz4cWjbBeSn0/sADAG+AzKiXv/z0uF9AA4BZgDLo9ra9doDBcD60P/9Qtv9UvwMRwCO0PYtUc8wMaRLbmBkSK/M7tKulH5Q2/GCzgZej9q/Crgq1Xa10fb/A+YDq4FBobZBwOrQ9n3AmVH9w/1SbPdQ4G3gMOCV0B/Z7qgPcfg9AV4HZoe2HaF+KsX254VEUDVpT5v3ISTkm0NC5gi9D0emy/sAlDQRwXa99sCZwH1R7TH9UvEMTY6dBDwR2o7RpMb3oru0K11cK40f6Ea2hNp6NKGfttOBRUCx1np76NAOoDi03VOf7TbgCsAK7fcHKrTWgdB+tJ3hZwgdrwz1TyUjgVLgkZB76EGlVBZp9D5orbcCtwKbgO3Yr+sS0ut9iKa9r32Pe0+acAH2LwlI8TOki5CnHUqpbOB54FKtdVX0MW1/NffYuE+l1HHALq31klTb0gkc2D+L79FaTwdqsX/Oh0mD96EfcCL2l9JgIAs4KqVGJYme/tq3hlLqaiAAPJFqWyB9hHwrMCxqf2iorUeilHJii/gTWusXQs07lVKDQscHAbtC7T3x2Q4ETlBKbQCewnav3A7kK6UcoT7RdoafIXQ8DyjrToMTsAXYorVeFNp/DlvY0+l9OBz4TmtdqrX2Ay9gvzfp9D5E097Xvie+JyilzgOOA84OfSFBip8hXYT8v8CY0Gy9C3si56UU25QQpZQCHgJWaq3/GnXoJaBx1v1cbN95Y/sPQzP3+wOVUT8/U4LW+iqt9VCtdQn2a/2O1vps4F3g1FC3ps/Q+GynhvqndLSltd4BbFZKjQs1zQNWkEbvA7ZLZX+lVGboc9X4DGnzPjShva/968ARSql+oV8nR4TaUoZS6ihsl+MJWuu6qEMvAWeEIodGAmOAz+ku7erOiYNOTjocgx0Bsg64OtX2tGDnQdg/Gb8Clob+HYPtq3wb+BZ4CygI9VfAXaHn+hqYmepnaPI8c4hErYwKfTjXAs8C7lC7J7S/NnR8VKrtDtk1DVgcei9exI58SKv3AbgeWAUsB/6JHRXR498H4Elsv74f+9fRjzry2mP7odeG/p3fA55hLbbPu/Fv+96o/leHnmE1cHRUe5drlyzRFwRBSHPSxbUiCIIgNIMIuSAIQpojQi4IgpDmiJALgiCkOSLkgiAIaY4IuSAIQpojQi4IgpDm/D952Htf0OOMKgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "rnn_preds = model(X_feature.unsqueeze(2))\n",
    "rnn_preds.squeeze()\n",
    "time = torch.arange(1, num+1, dtype= torch.float32)  # 时间轴\n",
    "\n",
    "plt.plot(time[:num-seq_len], x[seq_len:num], label='dji')\n",
    "# plt.plot(time[:num-seq_len], preds.detach().numpy(), label='preds')\n",
    "plt.plot(time[:num-seq_len], rnn_preds[:,seq_len-1].detach(), label='RNN_preds')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a0d2239",
   "metadata": {},
   "source": [
    "## 3 效果对比 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "2585d55c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 20/20 [00:59<00:00,  2.95s/it]\n"
     ]
    }
   ],
   "source": [
    "# 定义超参数\n",
    "input_size = 1\n",
    "output_size = 1\n",
    "num_hiddens = 64\n",
    "n_layers = 2\n",
    "lr = 0.001\n",
    "\n",
    "\n",
    "# 建立模型\n",
    "model_name = ['DRNN', 'BRNN', 'LSTM', 'GRU']\n",
    "drnn = DRNN(input_size, output_size, num_hiddens, n_layers)\n",
    "brnn = BRNN(input_size, output_size, num_hiddens, n_layers)\n",
    "lstm = LSTM(input_size, output_size, num_hiddens, n_layers)\n",
    "gru = GRU(input_size, output_size, num_hiddens, n_layers)\n",
    "models = [drnn, brnn, lstm, gru]\n",
    "\n",
    "opts = [torch.optim.Adam(drnn.parameters(), lr), \n",
    "            torch.optim.Adam(brnn.parameters(), lr), \n",
    "            torch.optim.Adam(lstm.parameters(), lr), \n",
    "            torch.optim.Adam(gru.parameters(), lr)]\n",
    "criterion = nn.MSELoss(reduction='none')\n",
    "\n",
    "num_epochs = 20\n",
    "rnn_loss_history = []\n",
    "lr = 0.1\n",
    "for epoch in tqdm(range(num_epochs)):\n",
    "    # 批量训练\n",
    "    for X, Y in train_loader:\n",
    "        for index, model, optimizer in zip(range(len(models)), models, opts):\n",
    "            y_pred = model(X)\n",
    "            loss = criterion(y_pred.squeeze(), Y.squeeze())\n",
    "            trainer.zero_grad()\n",
    "            loss.sum().backward()\n",
    "            trainer.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "417e5b47",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DRNN bias : tensor(125995.9453)\n",
      "BRNN bias : tensor(-24902.6758)\n",
      "LSTM bias : tensor(130150.6797)\n",
      "GRU bias : tensor(102981.3438)\n"
     ]
    }
   ],
   "source": [
    "for i in range(4):\n",
    "    rnn_preds = models[i](X_feature.unsqueeze(2))\n",
    "    bias = torch.sum(x[seq_len:num] - rnn_preds[:,seq_len-1].detach().numpy())\n",
    "    print ('{} bias : {}'.format(model_name[i],str(bias)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b9ea7c8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
